1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* 7*0Sstevel@tonic-gate * The contents of this file are subject to the Netscape Public 8*0Sstevel@tonic-gate * License Version 1.1 (the "License"); you may not use this file 9*0Sstevel@tonic-gate * except in compliance with the License. You may obtain a copy of 10*0Sstevel@tonic-gate * the License at http://www.mozilla.org/NPL/ 11*0Sstevel@tonic-gate * 12*0Sstevel@tonic-gate * Software distributed under the License is distributed on an "AS 13*0Sstevel@tonic-gate * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 14*0Sstevel@tonic-gate * implied. See the License for the specific language governing 15*0Sstevel@tonic-gate * rights and limitations under the License. 16*0Sstevel@tonic-gate * 17*0Sstevel@tonic-gate * The Original Code is Mozilla Communicator client code, released 18*0Sstevel@tonic-gate * March 31, 1998. 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * The Initial Developer of the Original Code is Netscape 21*0Sstevel@tonic-gate * Communications Corporation. Portions created by Netscape are 22*0Sstevel@tonic-gate * Copyright (C) 1998-1999 Netscape Communications Corporation. All 23*0Sstevel@tonic-gate * Rights Reserved. 24*0Sstevel@tonic-gate * 25*0Sstevel@tonic-gate * Contributor(s): 26*0Sstevel@tonic-gate */ 27*0Sstevel@tonic-gate 28*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * ldapsinit.c 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #if defined(NET_SSL) 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #if defined( _WINDOWS ) 37*0Sstevel@tonic-gate #include <windows.h> 38*0Sstevel@tonic-gate #endif 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate /* XXX:mhein The following is a workaround for the redefinition of */ 41*0Sstevel@tonic-gate /* const problem on OSF. Fix to be provided by NSS */ 42*0Sstevel@tonic-gate /* This is a pretty benign workaround for us which */ 43*0Sstevel@tonic-gate /* should not cause problems in the future even if */ 44*0Sstevel@tonic-gate /* we forget to take it out :-) */ 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate #ifdef OSF1V4D 47*0Sstevel@tonic-gate #ifndef __STDC__ 48*0Sstevel@tonic-gate # define __STDC__ 49*0Sstevel@tonic-gate #endif /* __STDC__ */ 50*0Sstevel@tonic-gate #endif /* OSF1V4D */ 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate #include <errno.h> 53*0Sstevel@tonic-gate #include <nspr.h> 54*0Sstevel@tonic-gate #include <cert.h> 55*0Sstevel@tonic-gate #include <key.h> 56*0Sstevel@tonic-gate #include <ssl.h> 57*0Sstevel@tonic-gate #include <sslproto.h> 58*0Sstevel@tonic-gate #include <sslerr.h> 59*0Sstevel@tonic-gate #include <prnetdb.h> 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate #include <ldap.h> 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate #include <ldappr.h> 64*0Sstevel@tonic-gate #include <pk11func.h> 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 67*0Sstevel@tonic-gate #include "solaris-int.h" 68*0Sstevel@tonic-gate #include <libintl.h> 69*0Sstevel@tonic-gate #include <syslog.h> 70*0Sstevel@tonic-gate #include <nsswitch.h> 71*0Sstevel@tonic-gate #include <synch.h> 72*0Sstevel@tonic-gate #include <nss_dbdefs.h> 73*0Sstevel@tonic-gate #include <netinet/in.h> 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate #define HOST_BUF_SIZE 2048 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gate #ifndef INADDR_NONE 78*0Sstevel@tonic-gate #define INADDR_NONE (-1) 79*0Sstevel@tonic-gate #endif 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate extern int 82*0Sstevel@tonic-gate str2hostent(const char *instr, int lenstr, void *ent, char *buffer, 83*0Sstevel@tonic-gate int buflen); 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate extern int 86*0Sstevel@tonic-gate str2hostent6(const char *instr, int lenstr, void *ent, char *buffer, 87*0Sstevel@tonic-gate int buflen); 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate extern LDAPHostEnt * 90*0Sstevel@tonic-gate _ns_gethostbyaddr(LDAP *ld, const char *addr, int length, int type, 91*0Sstevel@tonic-gate LDAPHostEnt *result, char *buffer, int buflen, int *statusp, 92*0Sstevel@tonic-gate void *extradata); 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate static char *host_service = NULL; 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_hosts); 97*0Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_ipnodes); 98*0Sstevel@tonic-gate #endif 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * Data structure to hold the standard NSPR I/O function pointers set by 102*0Sstevel@tonic-gate * libprldap. We save them in our session data structure so we can call 103*0Sstevel@tonic-gate * them from our own I/O functions (we add functionality to support SSL 104*0Sstevel@tonic-gate * while using libprldap's functions as much as possible). 105*0Sstevel@tonic-gate */ 106*0Sstevel@tonic-gate typedef struct ldapssl_std_functions { 107*0Sstevel@tonic-gate LDAP_X_EXTIOF_CLOSE_CALLBACK *lssf_close_fn; 108*0Sstevel@tonic-gate LDAP_X_EXTIOF_CONNECT_CALLBACK *lssf_connect_fn; 109*0Sstevel@tonic-gate LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK *lssf_disposehdl_fn; 110*0Sstevel@tonic-gate } LDAPSSLStdFunctions; 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * LDAP session data structure. 116*0Sstevel@tonic-gate */ 117*0Sstevel@tonic-gate typedef struct ldapssl_session_info { 118*0Sstevel@tonic-gate int lssei_using_pcks_fns; 119*0Sstevel@tonic-gate int lssei_ssl_strength; 120*0Sstevel@tonic-gate char *lssei_certnickname; 121*0Sstevel@tonic-gate char *lssei_keypasswd; 122*0Sstevel@tonic-gate LDAPSSLStdFunctions lssei_std_functions; 123*0Sstevel@tonic-gate CERTCertDBHandle *lssei_certdbh; 124*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * This is a hack. 127*0Sstevel@tonic-gate * ld is used so that we can use libldap's gethostbyaddr 128*0Sstevel@tonic-gate * resolver. This is needed to prevent recursion with libsldap. 129*0Sstevel@tonic-gate */ 130*0Sstevel@tonic-gate LDAP *ld; 131*0Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 132*0Sstevel@tonic-gate } LDAPSSLSessionInfo; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate /* 136*0Sstevel@tonic-gate * LDAP socket data structure. 137*0Sstevel@tonic-gate */ 138*0Sstevel@tonic-gate typedef struct ldapssl_socket_info { 139*0Sstevel@tonic-gate LDAPSSLSessionInfo *soi_sessioninfo; /* session info */ 140*0Sstevel@tonic-gate } LDAPSSLSocketInfo; 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate /* 144*0Sstevel@tonic-gate * XXXceb This is a hack until the new IO functions are done. 145*0Sstevel@tonic-gate * this function MUST be called before ldap_enable_clienauth. 146*0Sstevel@tonic-gate * right now, this function is called in ldapssl_pkcs_init(); 147*0Sstevel@tonic-gate */ 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate static int using_pkcs_functions = 0; 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate void set_using_pkcs_functions( int val ) 152*0Sstevel@tonic-gate { 153*0Sstevel@tonic-gate using_pkcs_functions = val; 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate /* 158*0Sstevel@tonic-gate * Utility functions: 159*0Sstevel@tonic-gate */ 160*0Sstevel@tonic-gate static void ldapssl_free_session_info( LDAPSSLSessionInfo **ssipp ); 161*0Sstevel@tonic-gate static void ldapssl_free_socket_info( LDAPSSLSocketInfo **soipp ); 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate /* 165*0Sstevel@tonic-gate * SSL Stuff 166*0Sstevel@tonic-gate */ 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate static int ldapssl_AuthCertificate(void *sessionarg, PRFileDesc *fd, 169*0Sstevel@tonic-gate PRBool checkSig, PRBool isServer); 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /* 172*0Sstevel@tonic-gate * client auth stuff 173*0Sstevel@tonic-gate */ 174*0Sstevel@tonic-gate static int get_clientauth_data( void *sessionarg, PRFileDesc *prfd, 175*0Sstevel@tonic-gate CERTDistNames *caNames, CERTCertificate **pRetCert, 176*0Sstevel@tonic-gate SECKEYPrivateKey **pRetKey ); 177*0Sstevel@tonic-gate static int get_keyandcert( LDAPSSLSessionInfo *ssip, 178*0Sstevel@tonic-gate CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey, 179*0Sstevel@tonic-gate char **errmsgp ); 180*0Sstevel@tonic-gate static int check_clientauth_nicknames_and_passwd( LDAP *ld, 181*0Sstevel@tonic-gate LDAPSSLSessionInfo *ssip ); 182*0Sstevel@tonic-gate static char *get_keypassword( PK11SlotInfo *slot, PRBool retry, 183*0Sstevel@tonic-gate void *sessionarg ); 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate /* 186*0Sstevel@tonic-gate * Static variables. 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 189*0Sstevel@tonic-gate static int default_ssl_strength = LDAPSSL_AUTH_CNCHECK; 190*0Sstevel@tonic-gate #else 191*0Sstevel@tonic-gate static int default_ssl_strength = LDAPSSL_AUTH_CERT; 192*0Sstevel@tonic-gate #endif 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate * Like ldap_init(), except also install I/O routines from libsec so we 196*0Sstevel@tonic-gate * can support SSL. If defsecure is non-zero, SSL is enabled for the 197*0Sstevel@tonic-gate * default connection as well. 198*0Sstevel@tonic-gate */ 199*0Sstevel@tonic-gate LDAP * 200*0Sstevel@tonic-gate LDAP_CALL 201*0Sstevel@tonic-gate ldapssl_init( const char *defhost, int defport, int defsecure ) 202*0Sstevel@tonic-gate { 203*0Sstevel@tonic-gate LDAP *ld; 204*0Sstevel@tonic-gate 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate #ifndef LDAP_SSLIO_HOOKS 207*0Sstevel@tonic-gate return( NULL ); 208*0Sstevel@tonic-gate #else 209*0Sstevel@tonic-gate if (0 ==defport) 210*0Sstevel@tonic-gate defport = LDAPS_PORT; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate if (( ld = ldap_init( defhost, defport )) == NULL ) { 213*0Sstevel@tonic-gate return( NULL ); 214*0Sstevel@tonic-gate } 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate if ( ldapssl_install_routines( ld ) < 0 || ldap_set_option( ld, 217*0Sstevel@tonic-gate LDAP_OPT_SSL, defsecure ? LDAP_OPT_ON : LDAP_OPT_OFF ) != 0 ) { 218*0Sstevel@tonic-gate PR_SetError( PR_UNKNOWN_ERROR, EINVAL ); /* XXXmcs: just a guess! */ 219*0Sstevel@tonic-gate ldap_unbind( ld ); 220*0Sstevel@tonic-gate return( NULL ); 221*0Sstevel@tonic-gate } 222*0Sstevel@tonic-gate 223*0Sstevel@tonic-gate return( ld ); 224*0Sstevel@tonic-gate #endif 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate static int 229*0Sstevel@tonic-gate ldapssl_close(int s, struct lextiof_socket_private *socketarg) 230*0Sstevel@tonic-gate { 231*0Sstevel@tonic-gate PRLDAPSocketInfo soi; 232*0Sstevel@tonic-gate LDAPSSLSocketInfo *ssoip; 233*0Sstevel@tonic-gate LDAPSSLSessionInfo *sseip; 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate memset( &soi, 0, sizeof(soi)); 236*0Sstevel@tonic-gate soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE; 237*0Sstevel@tonic-gate if ( prldap_get_socket_info( s, socketarg, &soi ) != LDAP_SUCCESS ) { 238*0Sstevel@tonic-gate return( -1 ); 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate ssoip = (LDAPSSLSocketInfo *)soi.soinfo_appdata; 242*0Sstevel@tonic-gate sseip = ssoip->soi_sessioninfo; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate ldapssl_free_socket_info( (LDAPSSLSocketInfo **)&soi.soinfo_appdata ); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate return( (*(sseip->lssei_std_functions.lssf_close_fn))( s, socketarg )); 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate static int 250*0Sstevel@tonic-gate do_ldapssl_connect(const char *hostlist, int defport, int timeout, 251*0Sstevel@tonic-gate unsigned long options, struct lextiof_session_private *sessionarg, 252*0Sstevel@tonic-gate struct lextiof_socket_private **socketargp, int clientauth ) 253*0Sstevel@tonic-gate { 254*0Sstevel@tonic-gate int intfd = -1; 255*0Sstevel@tonic-gate PRBool secure; 256*0Sstevel@tonic-gate PRLDAPSessionInfo sei; 257*0Sstevel@tonic-gate PRLDAPSocketInfo soi; 258*0Sstevel@tonic-gate LDAPSSLSocketInfo *ssoip = NULL; 259*0Sstevel@tonic-gate LDAPSSLSessionInfo *sseip; 260*0Sstevel@tonic-gate PRFileDesc *sslfd = NULL; 261*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 262*0Sstevel@tonic-gate int port; 263*0Sstevel@tonic-gate int parse_err; 264*0Sstevel@tonic-gate char *host = NULL; 265*0Sstevel@tonic-gate char *name; 266*0Sstevel@tonic-gate struct ldap_x_hostlist_status 267*0Sstevel@tonic-gate *status = NULL; 268*0Sstevel@tonic-gate in_addr_t addr_ipv4; 269*0Sstevel@tonic-gate in6_addr_t addr_ipv6; 270*0Sstevel@tonic-gate char *host_buf; 271*0Sstevel@tonic-gate LDAPHostEnt *hent; 272*0Sstevel@tonic-gate LDAPHostEnt host_ent; 273*0Sstevel@tonic-gate int stat; 274*0Sstevel@tonic-gate int type; 275*0Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * Determine if secure option is set. Also, clear secure bit in options 279*0Sstevel@tonic-gate * the we pass to the standard connect() function (since it doesn't know 280*0Sstevel@tonic-gate * how to handle the secure option). 281*0Sstevel@tonic-gate */ 282*0Sstevel@tonic-gate if ( 0 != ( options & LDAP_X_EXTIOF_OPT_SECURE )) { 283*0Sstevel@tonic-gate secure = PR_TRUE; 284*0Sstevel@tonic-gate options &= ~LDAP_X_EXTIOF_OPT_SECURE; 285*0Sstevel@tonic-gate } else { 286*0Sstevel@tonic-gate secure = PR_FALSE; 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate /* 290*0Sstevel@tonic-gate * Retrieve session info. so we can store a pointer to our session info. 291*0Sstevel@tonic-gate * in our socket info. later. 292*0Sstevel@tonic-gate */ 293*0Sstevel@tonic-gate memset( &sei, 0, sizeof(sei)); 294*0Sstevel@tonic-gate sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE; 295*0Sstevel@tonic-gate if ( prldap_get_session_info( NULL, sessionarg, &sei ) != LDAP_SUCCESS ) { 296*0Sstevel@tonic-gate return( -1 ); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * Call the standard connect() callback to make the TCP connection. 302*0Sstevel@tonic-gate * If it succeeds, *socketargp is set. 303*0Sstevel@tonic-gate */ 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate intfd = (*(sseip->lssei_std_functions.lssf_connect_fn))( hostlist, defport, 306*0Sstevel@tonic-gate timeout, options, sessionarg, socketargp 307*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 308*0Sstevel@tonic-gate , &host ); 309*0Sstevel@tonic-gate #else 310*0Sstevel@tonic-gate ); 311*0Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate if ( intfd < 0 ) { 314*0Sstevel@tonic-gate return( intfd ); 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 318*0Sstevel@tonic-gate /* 319*0Sstevel@tonic-gate * Determine if the "host name" is an ip address. If so, 320*0Sstevel@tonic-gate * we must look up the actual host name corresponding to 321*0Sstevel@tonic-gate * it. 322*0Sstevel@tonic-gate */ 323*0Sstevel@tonic-gate if ( NULL == host ) { 324*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 325*0Sstevel@tonic-gate } 326*0Sstevel@tonic-gate type = AF_UNSPEC; 327*0Sstevel@tonic-gate if (strlen(host) < INET6_ADDRSTRLEN && 328*0Sstevel@tonic-gate inet_pton(AF_INET6, host, &addr_ipv6) == 1) { 329*0Sstevel@tonic-gate type = AF_INET6; 330*0Sstevel@tonic-gate } else if (strlen(host) < INET_ADDRSTRLEN && 331*0Sstevel@tonic-gate inet_pton(AF_INET, host, &addr_ipv4) == 1) { 332*0Sstevel@tonic-gate type = AF_INET; 333*0Sstevel@tonic-gate } 334*0Sstevel@tonic-gate if (type == AF_INET || type == AF_INET6) { 335*0Sstevel@tonic-gate host_buf = malloc(HOST_BUF_SIZE); 336*0Sstevel@tonic-gate if (host_buf == NULL) { 337*0Sstevel@tonic-gate /* will free host in close_socket_and_exit_with_error */ 338*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate /* Call ldap layer's gethostbyaddr resolver */ 342*0Sstevel@tonic-gate hent = _ns_gethostbyaddr(sseip->ld, host, strlen(host), type, 343*0Sstevel@tonic-gate &host_ent, host_buf, HOST_BUF_SIZE, &stat, NULL); 344*0Sstevel@tonic-gate 345*0Sstevel@tonic-gate /* If we are unable to lookup the host addr, we fail! */ 346*0Sstevel@tonic-gate if (hent == NULL) { 347*0Sstevel@tonic-gate syslog(LOG_WARNING, 348*0Sstevel@tonic-gate "libldap: do_ldapssl_connect: " 349*0Sstevel@tonic-gate "Unable to resolve '%s'", host); 350*0Sstevel@tonic-gate free(host_buf); 351*0Sstevel@tonic-gate /* will free host in close_socket_and_exit_with_error */ 352*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate /* We support only the primary host name */ 355*0Sstevel@tonic-gate else { 356*0Sstevel@tonic-gate if (hent->ldaphe_name != NULL) 357*0Sstevel@tonic-gate name = strdup(hent->ldaphe_name); 358*0Sstevel@tonic-gate free(host_buf); 359*0Sstevel@tonic-gate if (name == NULL) 360*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 361*0Sstevel@tonic-gate else 362*0Sstevel@tonic-gate ldap_memfree(host); host = NULL; 363*0Sstevel@tonic-gate host = name; 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* 369*0Sstevel@tonic-gate * Retrieve socket info. so we have the PRFileDesc. 370*0Sstevel@tonic-gate */ 371*0Sstevel@tonic-gate memset( &soi, 0, sizeof(soi)); 372*0Sstevel@tonic-gate soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE; 373*0Sstevel@tonic-gate if ( prldap_get_socket_info( intfd, *socketargp, &soi ) != LDAP_SUCCESS ) { 374*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate /* 378*0Sstevel@tonic-gate * Allocate a structure to hold our socket-specific data. 379*0Sstevel@tonic-gate */ 380*0Sstevel@tonic-gate if ( NULL == ( ssoip = PR_Calloc( 1, sizeof( LDAPSSLSocketInfo )))) { 381*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate ssoip->soi_sessioninfo = sseip; 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate /* 386*0Sstevel@tonic-gate * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL. 387*0Sstevel@tonic-gate */ 388*0Sstevel@tonic-gate if (( sslfd = SSL_ImportFD( NULL, soi.soinfo_prfd )) == NULL ) { 389*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 390*0Sstevel@tonic-gate } 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate if ( SSL_OptionSet( sslfd, SSL_SECURITY, secure ) != SECSuccess || 393*0Sstevel@tonic-gate SSL_OptionSet( sslfd, SSL_HANDSHAKE_AS_CLIENT, secure ) 394*0Sstevel@tonic-gate != SECSuccess || ( secure && SSL_ResetHandshake( sslfd, 395*0Sstevel@tonic-gate PR_FALSE ) != SECSuccess )) { 396*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate /* 400*0Sstevel@tonic-gate * Let the standard NSPR to LDAP layer know about the new socket and 401*0Sstevel@tonic-gate * our own socket-specific data. 402*0Sstevel@tonic-gate */ 403*0Sstevel@tonic-gate soi.soinfo_prfd = sslfd; 404*0Sstevel@tonic-gate soi.soinfo_appdata = (void *)ssoip; 405*0Sstevel@tonic-gate if ( prldap_set_socket_info( intfd, *socketargp, &soi ) != LDAP_SUCCESS ) { 406*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 407*0Sstevel@tonic-gate } 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 410*0Sstevel@tonic-gate /* 411*0Sstevel@tonic-gate * Set hostname which will be retrieved (depending on ssl strength) when 412*0Sstevel@tonic-gate * using client or server auth. 413*0Sstevel@tonic-gate */ 414*0Sstevel@tonic-gate if (SSL_SetURL(sslfd, host) != SECSuccess) 415*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 416*0Sstevel@tonic-gate ldap_memfree(host); 417*0Sstevel@tonic-gate host = NULL; 418*0Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 419*0Sstevel@tonic-gate 420*0Sstevel@tonic-gate sslfd = NULL; /* so we don't close the socket twice upon error */ 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * Install certificate hook function. 424*0Sstevel@tonic-gate */ 425*0Sstevel@tonic-gate SSL_AuthCertificateHook( soi.soinfo_prfd, 426*0Sstevel@tonic-gate (SSLAuthCertificate)ldapssl_AuthCertificate, 427*0Sstevel@tonic-gate (void *)sseip); 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate if ( SSL_GetClientAuthDataHook( soi.soinfo_prfd, 430*0Sstevel@tonic-gate get_clientauth_data, clientauth ? sseip : NULL ) != 0 ) { 431*0Sstevel@tonic-gate goto close_socket_and_exit_with_error; 432*0Sstevel@tonic-gate } 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate return( intfd ); /* success */ 435*0Sstevel@tonic-gate 436*0Sstevel@tonic-gate close_socket_and_exit_with_error: 437*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 438*0Sstevel@tonic-gate if ( NULL != host ) ldap_memfree(host); 439*0Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 440*0Sstevel@tonic-gate if ( NULL != sslfd ) { 441*0Sstevel@tonic-gate PR_Close( sslfd ); 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate if ( NULL != ssoip ) { 444*0Sstevel@tonic-gate ldapssl_free_socket_info( &ssoip ); 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate if ( intfd >= 0 && NULL != *socketargp ) { 447*0Sstevel@tonic-gate (*(sseip->lssei_std_functions.lssf_close_fn))( intfd, *socketargp ); 448*0Sstevel@tonic-gate } 449*0Sstevel@tonic-gate return( -1 ); 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate static int 454*0Sstevel@tonic-gate ldapssl_connect(const char *hostlist, int defport, int timeout, 455*0Sstevel@tonic-gate unsigned long options, struct lextiof_session_private *sessionarg, 456*0Sstevel@tonic-gate struct lextiof_socket_private **socketargp ) 457*0Sstevel@tonic-gate { 458*0Sstevel@tonic-gate return( do_ldapssl_connect( hostlist, defport, timeout, options, 459*0Sstevel@tonic-gate sessionarg, socketargp, 0 )); 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate static int 464*0Sstevel@tonic-gate ldapssl_clientauth_connect(const char *hostlist, int defport, int timeout, 465*0Sstevel@tonic-gate unsigned long options, struct lextiof_session_private *sessionarg, 466*0Sstevel@tonic-gate struct lextiof_socket_private **socketargp ) 467*0Sstevel@tonic-gate { 468*0Sstevel@tonic-gate return( do_ldapssl_connect( hostlist, defport, timeout, options, 469*0Sstevel@tonic-gate sessionarg, socketargp, 1 )); 470*0Sstevel@tonic-gate } 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate static void 474*0Sstevel@tonic-gate ldapssl_disposehandle(LDAP *ld, struct lextiof_session_private *sessionarg) 475*0Sstevel@tonic-gate { 476*0Sstevel@tonic-gate PRLDAPSessionInfo sei; 477*0Sstevel@tonic-gate LDAPSSLSessionInfo *sseip; 478*0Sstevel@tonic-gate LDAP_X_EXTIOF_DISPOSEHANDLE_CALLBACK *disposehdl_fn; 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate memset( &sei, 0, sizeof( sei )); 481*0Sstevel@tonic-gate sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE; 482*0Sstevel@tonic-gate if ( prldap_get_session_info( ld, NULL, &sei ) == LDAP_SUCCESS ) { 483*0Sstevel@tonic-gate sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata; 484*0Sstevel@tonic-gate disposehdl_fn = sseip->lssei_std_functions.lssf_disposehdl_fn; 485*0Sstevel@tonic-gate ldapssl_free_session_info( &sseip ); 486*0Sstevel@tonic-gate (*disposehdl_fn)( ld, sessionarg ); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate /* 492*0Sstevel@tonic-gate * Install I/O routines from libsec and NSPR into libldap to allow libldap 493*0Sstevel@tonic-gate * to do SSL. 494*0Sstevel@tonic-gate * 495*0Sstevel@tonic-gate * We rely on libprldap to provide most of the functions, and then we override 496*0Sstevel@tonic-gate * a few of them to support SSL. 497*0Sstevel@tonic-gate */ 498*0Sstevel@tonic-gate int 499*0Sstevel@tonic-gate LDAP_CALL 500*0Sstevel@tonic-gate ldapssl_install_routines( LDAP *ld ) 501*0Sstevel@tonic-gate { 502*0Sstevel@tonic-gate #ifndef LDAP_SSLIO_HOOKS 503*0Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 504*0Sstevel@tonic-gate return( -1 ); 505*0Sstevel@tonic-gate #else 506*0Sstevel@tonic-gate struct ldap_x_ext_io_fns iofns; 507*0Sstevel@tonic-gate LDAPSSLSessionInfo *ssip; 508*0Sstevel@tonic-gate PRLDAPSessionInfo sei; 509*0Sstevel@tonic-gate 510*0Sstevel@tonic-gate /* 511*0Sstevel@tonic-gate * This is done within ldap_init() and 512*0Sstevel@tonic-gate * ldap_init() is called from ldapssl_init() 513*0Sstevel@tonic-gate */ 514*0Sstevel@tonic-gate #ifndef _SOLARIS_SDK 515*0Sstevel@tonic-gate if ( prldap_install_routines( 516*0Sstevel@tonic-gate ld, 517*0Sstevel@tonic-gate 1 /* shared -- we have to assume it is */ ) 518*0Sstevel@tonic-gate != LDAP_SUCCESS ) { 519*0Sstevel@tonic-gate return( -1 ); 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate #endif /*_SOLARIS_SDK*/ 522*0Sstevel@tonic-gate 523*0Sstevel@tonic-gate /* 524*0Sstevel@tonic-gate * Allocate our own session information. 525*0Sstevel@tonic-gate */ 526*0Sstevel@tonic-gate if ( NULL == ( ssip = (LDAPSSLSessionInfo *)PR_Calloc( 1, 527*0Sstevel@tonic-gate sizeof( LDAPSSLSessionInfo )))) { 528*0Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL ); 529*0Sstevel@tonic-gate return( -1 ); 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate /* 532*0Sstevel@tonic-gate * Initialize session info. 533*0Sstevel@tonic-gate * XXX: it would be nice to be able to set these on a per-session basis: 534*0Sstevel@tonic-gate * lssei_using_pcks_fns 535*0Sstevel@tonic-gate * lssei_certdbh 536*0Sstevel@tonic-gate */ 537*0Sstevel@tonic-gate ssip->lssei_ssl_strength = default_ssl_strength; 538*0Sstevel@tonic-gate ssip->lssei_using_pcks_fns = using_pkcs_functions; 539*0Sstevel@tonic-gate ssip->lssei_certdbh = CERT_GetDefaultCertDB(); 540*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 541*0Sstevel@tonic-gate /* 542*0Sstevel@tonic-gate * This is part of a hack to allow the ssl portion of the 543*0Sstevel@tonic-gate * library to call the ldap library gethostbyaddr resolver. 544*0Sstevel@tonic-gate */ 545*0Sstevel@tonic-gate ssip->ld = ld; 546*0Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate /* 549*0Sstevel@tonic-gate * override a few functions, saving a pointer to the standard function 550*0Sstevel@tonic-gate * in each case so we can call it from our SSL savvy functions. 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate memset( &iofns, 0, sizeof(iofns)); 553*0Sstevel@tonic-gate iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 554*0Sstevel@tonic-gate if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) { 555*0Sstevel@tonic-gate ldapssl_free_session_info( &ssip ); 556*0Sstevel@tonic-gate return( -1 ); 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate /* override socket, connect, and ioctl */ 560*0Sstevel@tonic-gate ssip->lssei_std_functions.lssf_connect_fn = iofns.lextiof_connect; 561*0Sstevel@tonic-gate iofns.lextiof_connect = ldapssl_connect; 562*0Sstevel@tonic-gate ssip->lssei_std_functions.lssf_close_fn = iofns.lextiof_close; 563*0Sstevel@tonic-gate iofns.lextiof_close = ldapssl_close; 564*0Sstevel@tonic-gate ssip->lssei_std_functions.lssf_disposehdl_fn = iofns.lextiof_disposehandle; 565*0Sstevel@tonic-gate iofns.lextiof_disposehandle = ldapssl_disposehandle; 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) < 0 ) { 568*0Sstevel@tonic-gate ldapssl_free_session_info( &ssip ); 569*0Sstevel@tonic-gate return( -1 ); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate /* 573*0Sstevel@tonic-gate * Store session info. for later retrieval. 574*0Sstevel@tonic-gate */ 575*0Sstevel@tonic-gate sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE; 576*0Sstevel@tonic-gate sei.seinfo_appdata = (void *)ssip; 577*0Sstevel@tonic-gate if ( prldap_set_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) { 578*0Sstevel@tonic-gate return( -1 ); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate return( 0 ); 582*0Sstevel@tonic-gate #endif 583*0Sstevel@tonic-gate } 584*0Sstevel@tonic-gate 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate /* 587*0Sstevel@tonic-gate * Set the SSL strength for an existing SSL-enabled LDAP session handle. 588*0Sstevel@tonic-gate * 589*0Sstevel@tonic-gate * See the description of ldapssl_serverauth_init() above for valid 590*0Sstevel@tonic-gate * sslstrength values. If ld is NULL, the default for new LDAP session 591*0Sstevel@tonic-gate * handles is set. 592*0Sstevel@tonic-gate * 593*0Sstevel@tonic-gate * Returns 0 if all goes well and -1 if an error occurs. 594*0Sstevel@tonic-gate */ 595*0Sstevel@tonic-gate int 596*0Sstevel@tonic-gate LDAP_CALL 597*0Sstevel@tonic-gate ldapssl_set_strength( LDAP *ld, int sslstrength ) 598*0Sstevel@tonic-gate { 599*0Sstevel@tonic-gate int rc = 0; /* assume success */ 600*0Sstevel@tonic-gate 601*0Sstevel@tonic-gate if ( sslstrength != LDAPSSL_AUTH_WEAK && 602*0Sstevel@tonic-gate sslstrength != LDAPSSL_AUTH_CERT && 603*0Sstevel@tonic-gate sslstrength != LDAPSSL_AUTH_CNCHECK ) { 604*0Sstevel@tonic-gate rc = -1; 605*0Sstevel@tonic-gate } else { 606*0Sstevel@tonic-gate if ( NULL == ld ) { /* set default strength */ 607*0Sstevel@tonic-gate default_ssl_strength = sslstrength; 608*0Sstevel@tonic-gate } else { /* set session-specific strength */ 609*0Sstevel@tonic-gate PRLDAPSessionInfo sei; 610*0Sstevel@tonic-gate LDAPSSLSessionInfo *sseip; 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate memset( &sei, 0, sizeof( sei )); 613*0Sstevel@tonic-gate sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE; 614*0Sstevel@tonic-gate if ( prldap_get_session_info( ld, NULL, &sei ) == LDAP_SUCCESS ) 615*0Sstevel@tonic-gate { 616*0Sstevel@tonic-gate sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata; 617*0Sstevel@tonic-gate sseip->lssei_ssl_strength = sslstrength; 618*0Sstevel@tonic-gate } else { 619*0Sstevel@tonic-gate rc = -1; 620*0Sstevel@tonic-gate } 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate return( rc ); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate 627*0Sstevel@tonic-gate int 628*0Sstevel@tonic-gate LDAP_CALL 629*0Sstevel@tonic-gate ldapssl_enable_clientauth( LDAP *ld, char *keynickname, 630*0Sstevel@tonic-gate char *keypasswd, char *certnickname ) 631*0Sstevel@tonic-gate { 632*0Sstevel@tonic-gate #ifndef LDAP_SSLIO_HOOKS 633*0Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_LOCAL_ERROR, NULL, NULL ); 634*0Sstevel@tonic-gate return( -1 ); 635*0Sstevel@tonic-gate #else 636*0Sstevel@tonic-gate struct ldap_x_ext_io_fns iofns; 637*0Sstevel@tonic-gate LDAPSSLSessionInfo *ssip; 638*0Sstevel@tonic-gate PRLDAPSessionInfo sei; 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate /* 641*0Sstevel@tonic-gate * Check parameters 642*0Sstevel@tonic-gate */ 643*0Sstevel@tonic-gate if ( certnickname == NULL || keypasswd == NULL ) { 644*0Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL ); 645*0Sstevel@tonic-gate return( -1 ); 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* 649*0Sstevel@tonic-gate * Update session info. data structure. 650*0Sstevel@tonic-gate */ 651*0Sstevel@tonic-gate sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE; 652*0Sstevel@tonic-gate if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) { 653*0Sstevel@tonic-gate return( -1 ); 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate ssip = (LDAPSSLSessionInfo *)sei.seinfo_appdata; 656*0Sstevel@tonic-gate if ( NULL == ssip ) { 657*0Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL ); 658*0Sstevel@tonic-gate return( -1 ); 659*0Sstevel@tonic-gate } 660*0Sstevel@tonic-gate ssip->lssei_certnickname = PL_strdup( certnickname ); 661*0Sstevel@tonic-gate ssip->lssei_keypasswd = PL_strdup( keypasswd ); 662*0Sstevel@tonic-gate 663*0Sstevel@tonic-gate if ( NULL == ssip->lssei_certnickname || NULL == ssip->lssei_keypasswd ) { 664*0Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_NO_MEMORY, NULL, NULL ); 665*0Sstevel@tonic-gate return( -1 ); 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate if ( check_clientauth_nicknames_and_passwd( ld, ssip ) != 0 ) { 669*0Sstevel@tonic-gate return( -1 ); 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate /* 673*0Sstevel@tonic-gate * replace standard SSL CONNECT function with client auth aware one 674*0Sstevel@tonic-gate */ 675*0Sstevel@tonic-gate memset( &iofns, 0, sizeof(iofns)); 676*0Sstevel@tonic-gate iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 677*0Sstevel@tonic-gate if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) 678*0Sstevel@tonic-gate != 0 ) { 679*0Sstevel@tonic-gate return( -1 ); 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate 682*0Sstevel@tonic-gate if ( iofns.lextiof_connect != ldapssl_connect ) { 683*0Sstevel@tonic-gate /* standard SSL setup has not done */ 684*0Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, NULL ); 685*0Sstevel@tonic-gate return( -1 ); 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate iofns.lextiof_connect = ldapssl_clientauth_connect; 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) 691*0Sstevel@tonic-gate != 0 ) { 692*0Sstevel@tonic-gate return( -1 ); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate return( 0 ); 696*0Sstevel@tonic-gate #endif 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate static void 701*0Sstevel@tonic-gate ldapssl_free_session_info( LDAPSSLSessionInfo **ssipp ) 702*0Sstevel@tonic-gate { 703*0Sstevel@tonic-gate if ( NULL != ssipp && NULL != *ssipp ) { 704*0Sstevel@tonic-gate if ( NULL != (*ssipp)->lssei_certnickname ) { 705*0Sstevel@tonic-gate PL_strfree( (*ssipp)->lssei_certnickname ); 706*0Sstevel@tonic-gate (*ssipp)->lssei_certnickname = NULL; 707*0Sstevel@tonic-gate } 708*0Sstevel@tonic-gate if ( NULL != (*ssipp)->lssei_keypasswd ) { 709*0Sstevel@tonic-gate PL_strfree( (*ssipp)->lssei_keypasswd ); 710*0Sstevel@tonic-gate (*ssipp)->lssei_keypasswd = NULL; 711*0Sstevel@tonic-gate } 712*0Sstevel@tonic-gate PR_Free( *ssipp ); 713*0Sstevel@tonic-gate *ssipp = NULL; 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate static void 719*0Sstevel@tonic-gate ldapssl_free_socket_info( LDAPSSLSocketInfo **soipp ) 720*0Sstevel@tonic-gate { 721*0Sstevel@tonic-gate if ( NULL != soipp && NULL != *soipp ) { 722*0Sstevel@tonic-gate PR_Free( *soipp ); 723*0Sstevel@tonic-gate *soipp = NULL; 724*0Sstevel@tonic-gate } 725*0Sstevel@tonic-gate } 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate /* this function provides cert authentication. This is called during 729*0Sstevel@tonic-gate * the SSL_Handshake process. Once the cert has been retrieved from 730*0Sstevel@tonic-gate * the server, the it is checked, using VerifyCertNow(), then 731*0Sstevel@tonic-gate * the cn is checked against the host name, set with SSL_SetURL() 732*0Sstevel@tonic-gate */ 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate static int 735*0Sstevel@tonic-gate ldapssl_AuthCertificate(void *sessionarg, PRFileDesc *fd, PRBool checkSig, 736*0Sstevel@tonic-gate PRBool isServer) 737*0Sstevel@tonic-gate { 738*0Sstevel@tonic-gate SECStatus rv = SECFailure; 739*0Sstevel@tonic-gate LDAPSSLSessionInfo *sseip; 740*0Sstevel@tonic-gate CERTCertificate *cert; 741*0Sstevel@tonic-gate SECCertUsage certUsage; 742*0Sstevel@tonic-gate char *hostname = (char *)0; 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate if (!sessionarg || !socket) 745*0Sstevel@tonic-gate return rv; 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate sseip = (LDAPSSLSessionInfo *)sessionarg; 748*0Sstevel@tonic-gate 749*0Sstevel@tonic-gate if (LDAPSSL_AUTH_WEAK == sseip->lssei_ssl_strength ) { /* no check */ 750*0Sstevel@tonic-gate return SECSuccess; 751*0Sstevel@tonic-gate } 752*0Sstevel@tonic-gate 753*0Sstevel@tonic-gate if ( isServer ) { 754*0Sstevel@tonic-gate certUsage = certUsageSSLClient; 755*0Sstevel@tonic-gate } else { 756*0Sstevel@tonic-gate certUsage = certUsageSSLServer; 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate cert = SSL_PeerCertificate( fd ); 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate rv = CERT_VerifyCertNow(sseip->lssei_certdbh, cert, checkSig, 761*0Sstevel@tonic-gate certUsage, NULL); 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate if ( rv != SECSuccess || isServer ) 764*0Sstevel@tonic-gate return rv; 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate if ( LDAPSSL_AUTH_CNCHECK == sseip->lssei_ssl_strength ) 767*0Sstevel@tonic-gate { 768*0Sstevel@tonic-gate /* cert is OK. This is the client side of an SSL connection. 769*0Sstevel@tonic-gate * Now check the name field in the cert against the desired hostname. 770*0Sstevel@tonic-gate * NB: This is our only defense against Man-In-The-Middle (MITM) 771*0Sstevel@tonic-gate * attacks! 772*0Sstevel@tonic-gate */ 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate hostname = SSL_RevealURL( fd ); 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate if (hostname && hostname[0]) { 777*0Sstevel@tonic-gate rv = CERT_VerifyCertName(cert, hostname); 778*0Sstevel@tonic-gate } else { 779*0Sstevel@tonic-gate rv = SECFailure; 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate if (hostname) 782*0Sstevel@tonic-gate PORT_Free(hostname); 783*0Sstevel@tonic-gate if (rv != SECSuccess) 784*0Sstevel@tonic-gate PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); 785*0Sstevel@tonic-gate } 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate return((int)rv); 788*0Sstevel@tonic-gate } 789*0Sstevel@tonic-gate 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate /* 792*0Sstevel@tonic-gate * called during SSL client auth. when server wants our cert and key. 793*0Sstevel@tonic-gate * return 0 if we succeeded and set *pRetCert and *pRetKey, -1 otherwise. 794*0Sstevel@tonic-gate * if -1 is returned SSL will proceed without sending a cert. 795*0Sstevel@tonic-gate */ 796*0Sstevel@tonic-gate 797*0Sstevel@tonic-gate static int 798*0Sstevel@tonic-gate get_clientauth_data( void *sessionarg, PRFileDesc *prfd, 799*0Sstevel@tonic-gate CERTDistNames *caNames, CERTCertificate **pRetCert, 800*0Sstevel@tonic-gate SECKEYPrivateKey **pRetKey ) 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate { 803*0Sstevel@tonic-gate LDAPSSLSessionInfo *ssip; 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate if (( ssip = (LDAPSSLSessionInfo *)sessionarg ) == NULL ) { 806*0Sstevel@tonic-gate return( -1 ); /* client auth. not enabled */ 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate return( get_keyandcert( ssip, pRetCert, pRetKey, NULL )); 810*0Sstevel@tonic-gate } 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate static int 813*0Sstevel@tonic-gate get_keyandcert( LDAPSSLSessionInfo *ssip, 814*0Sstevel@tonic-gate CERTCertificate **pRetCert, SECKEYPrivateKey **pRetKey, 815*0Sstevel@tonic-gate char **errmsgp ) 816*0Sstevel@tonic-gate { 817*0Sstevel@tonic-gate CERTCertificate *cert; 818*0Sstevel@tonic-gate SECKEYPrivateKey *key; 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate if (( cert = PK11_FindCertFromNickname( ssip->lssei_certnickname, NULL )) 821*0Sstevel@tonic-gate == NULL ) { 822*0Sstevel@tonic-gate if ( errmsgp != NULL ) { 823*0Sstevel@tonic-gate *errmsgp = dgettext(TEXT_DOMAIN, "unable to find certificate"); 824*0Sstevel@tonic-gate } 825*0Sstevel@tonic-gate return( -1 ); 826*0Sstevel@tonic-gate } 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate { 829*0Sstevel@tonic-gate PK11_SetPasswordFunc( get_keypassword ); 830*0Sstevel@tonic-gate } 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate if (( key = PK11_FindKeyByAnyCert( cert, (void *)ssip )) == NULL ) { 835*0Sstevel@tonic-gate CERT_DestroyCertificate( cert ); 836*0Sstevel@tonic-gate if ( errmsgp != NULL ) { 837*0Sstevel@tonic-gate *errmsgp = dgettext(TEXT_DOMAIN, "bad key or key password"); 838*0Sstevel@tonic-gate } 839*0Sstevel@tonic-gate return( -1 ); 840*0Sstevel@tonic-gate } 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate *pRetCert = cert; 843*0Sstevel@tonic-gate *pRetKey = key; 844*0Sstevel@tonic-gate return( 0 ); 845*0Sstevel@tonic-gate } 846*0Sstevel@tonic-gate 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate /* 849*0Sstevel@tonic-gate * This function returns the password to NSS. 850*0Sstevel@tonic-gate * This function is enable through PK11_SetPasswordFunc 851*0Sstevel@tonic-gate * only if pkcs functions are not being used. 852*0Sstevel@tonic-gate */ 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate static char * 855*0Sstevel@tonic-gate get_keypassword( PK11SlotInfo *slot, PRBool retry, void *sessionarg ) 856*0Sstevel@tonic-gate { 857*0Sstevel@tonic-gate LDAPSSLSessionInfo *ssip; 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate if ( retry) 860*0Sstevel@tonic-gate return (NULL); 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate ssip = (LDAPSSLSessionInfo *)sessionarg; 863*0Sstevel@tonic-gate if ( NULL == ssip ) { 864*0Sstevel@tonic-gate return( NULL ); 865*0Sstevel@tonic-gate } 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate return( ssip->lssei_keypasswd ); 868*0Sstevel@tonic-gate } 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate 871*0Sstevel@tonic-gate /* 872*0Sstevel@tonic-gate * performs some basic checks on clientauth cert and key/password 873*0Sstevel@tonic-gate * 874*0Sstevel@tonic-gate * XXXmcs: could perform additional checks... see servers/slapd/ssl.c 875*0Sstevel@tonic-gate * 1) check expiration 876*0Sstevel@tonic-gate * 2) check that public key in cert matches private key 877*0Sstevel@tonic-gate * see ns/netsite/ldap/servers/slapd/ssl.c:slapd_ssl_init() for example code. 878*0Sstevel@tonic-gate */ 879*0Sstevel@tonic-gate static int 880*0Sstevel@tonic-gate check_clientauth_nicknames_and_passwd( LDAP *ld, LDAPSSLSessionInfo *ssip ) 881*0Sstevel@tonic-gate { 882*0Sstevel@tonic-gate char *errmsg = NULL; 883*0Sstevel@tonic-gate CERTCertificate *cert = NULL; 884*0Sstevel@tonic-gate SECKEYPrivateKey *key = NULL; 885*0Sstevel@tonic-gate int rv; 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate rv = get_keyandcert( ssip, &cert, &key, &errmsg ); 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate if ( rv != 0 ) { 890*0Sstevel@tonic-gate if ( errmsg != NULL ) { 891*0Sstevel@tonic-gate errmsg = strdup( errmsg ); 892*0Sstevel@tonic-gate } 893*0Sstevel@tonic-gate ldap_set_lderrno( ld, LDAP_PARAM_ERROR, NULL, errmsg ); 894*0Sstevel@tonic-gate return( -1 ); 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate if ( cert != NULL ) { 898*0Sstevel@tonic-gate CERT_DestroyCertificate( cert ); 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate if ( key != NULL ) { 901*0Sstevel@tonic-gate SECKEY_DestroyPrivateKey( key ); 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate return( 0 ); 904*0Sstevel@tonic-gate } 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate #if 0 /* NOT_NEEDED_IN_LIBLDAP */ 908*0Sstevel@tonic-gate /* there are patches and kludges. this is both. force some linkers to 909*0Sstevel@tonic-gate * link this stuff in 910*0Sstevel@tonic-gate */ 911*0Sstevel@tonic-gate int stubs_o_stuff( void ) 912*0Sstevel@tonic-gate { 913*0Sstevel@tonic-gate PRExplodedTime exploded; 914*0Sstevel@tonic-gate PLArenaPool pool; 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate const char *name ="t"; 917*0Sstevel@tonic-gate PRUint32 size = 0, align = 0; 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate PR_ImplodeTime( &exploded ); 920*0Sstevel@tonic-gate PL_InitArenaPool( &pool, name, size, align); 921*0Sstevel@tonic-gate PR_Cleanup(); 922*0Sstevel@tonic-gate PR_fprintf((PRFileDesc*)stderr, "Bad IDEA!!"); 923*0Sstevel@tonic-gate 924*0Sstevel@tonic-gate return 0; 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate } 927*0Sstevel@tonic-gate #endif /* NOT_NEEDED_IN_LIBLDAP */ 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate /* 931*0Sstevel@tonic-gate * Import the file descriptor corresponding to the socket of an already 932*0Sstevel@tonic-gate * open LDAP connection into SSL, and update the socket and session 933*0Sstevel@tonic-gate * information accordingly. 934*0Sstevel@tonic-gate */ 935*0Sstevel@tonic-gate int ldapssl_import_fd ( LDAP *ld, int secure ) 936*0Sstevel@tonic-gate { 937*0Sstevel@tonic-gate PRLDAPSessionInfo sei; 938*0Sstevel@tonic-gate PRLDAPSocketInfo soi; 939*0Sstevel@tonic-gate LDAPSSLSocketInfo *ssoip = NULL; 940*0Sstevel@tonic-gate LDAPSSLSessionInfo *sseip; 941*0Sstevel@tonic-gate PRFileDesc *sslfd = NULL; 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate /* 945*0Sstevel@tonic-gate * Retrieve session info. so we can store a pointer to our session info. 946*0Sstevel@tonic-gate * in our socket info. later. 947*0Sstevel@tonic-gate */ 948*0Sstevel@tonic-gate memset( &sei, 0, sizeof(sei)); 949*0Sstevel@tonic-gate sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE; 950*0Sstevel@tonic-gate if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) { 951*0Sstevel@tonic-gate return( -1 ); 952*0Sstevel@tonic-gate } 953*0Sstevel@tonic-gate sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata; 954*0Sstevel@tonic-gate 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate /* 957*0Sstevel@tonic-gate * Retrieve socket info. so we have the PRFileDesc. 958*0Sstevel@tonic-gate */ 959*0Sstevel@tonic-gate memset( &soi, 0, sizeof(soi)); 960*0Sstevel@tonic-gate soi.soinfo_size = PRLDAP_SOCKETINFO_SIZE; 961*0Sstevel@tonic-gate if ( prldap_get_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) { 962*0Sstevel@tonic-gate return( -1 ); 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate /* 966*0Sstevel@tonic-gate * Allocate a structure to hold our socket-specific data. 967*0Sstevel@tonic-gate */ 968*0Sstevel@tonic-gate if ( NULL == ( ssoip = PR_Calloc( 1, sizeof( LDAPSSLSocketInfo )))) { 969*0Sstevel@tonic-gate goto reset_socket_and_exit_with_error; 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate ssoip->soi_sessioninfo = sseip; 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate /* 974*0Sstevel@tonic-gate * Add SSL layer and let the standard NSPR to LDAP layer and enable SSL. 975*0Sstevel@tonic-gate */ 976*0Sstevel@tonic-gate if (( sslfd = SSL_ImportFD( NULL, soi.soinfo_prfd )) == NULL ) { 977*0Sstevel@tonic-gate goto reset_socket_and_exit_with_error; 978*0Sstevel@tonic-gate } 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate if ( SSL_OptionSet( sslfd, SSL_SECURITY, secure ) != SECSuccess || 981*0Sstevel@tonic-gate SSL_OptionSet( sslfd, SSL_HANDSHAKE_AS_CLIENT, secure ) 982*0Sstevel@tonic-gate != SECSuccess || ( secure && SSL_ResetHandshake( sslfd, 983*0Sstevel@tonic-gate PR_FALSE ) != SECSuccess )) { 984*0Sstevel@tonic-gate goto reset_socket_and_exit_with_error; 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate 987*0Sstevel@tonic-gate /* 988*0Sstevel@tonic-gate * Let the standard NSPR to LDAP layer know about the new socket and 989*0Sstevel@tonic-gate * our own socket-specific data. 990*0Sstevel@tonic-gate */ 991*0Sstevel@tonic-gate soi.soinfo_prfd = sslfd; 992*0Sstevel@tonic-gate soi.soinfo_appdata = (void *)ssoip; 993*0Sstevel@tonic-gate if ( prldap_set_default_socket_info( ld, &soi ) != LDAP_SUCCESS ) { 994*0Sstevel@tonic-gate goto reset_socket_and_exit_with_error; 995*0Sstevel@tonic-gate } 996*0Sstevel@tonic-gate 997*0Sstevel@tonic-gate /* 998*0Sstevel@tonic-gate * Install certificate hook function. 999*0Sstevel@tonic-gate */ 1000*0Sstevel@tonic-gate if ( SSL_AuthCertificateHook( soi.soinfo_prfd, 1001*0Sstevel@tonic-gate (SSLAuthCertificate)ldapssl_AuthCertificate, 1002*0Sstevel@tonic-gate (void *)CERT_GetDefaultCertDB()) != 0 ) { 1003*0Sstevel@tonic-gate goto reset_socket_and_exit_with_error; 1004*0Sstevel@tonic-gate } 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate if ( SSL_GetClientAuthDataHook( soi.soinfo_prfd, 1007*0Sstevel@tonic-gate get_clientauth_data, sseip->lssei_certnickname ? sseip : NULL ) 1008*0Sstevel@tonic-gate != 0 ) { 1009*0Sstevel@tonic-gate goto reset_socket_and_exit_with_error; 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate return 0; 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate reset_socket_and_exit_with_error: 1015*0Sstevel@tonic-gate if ( NULL != sslfd ) { 1016*0Sstevel@tonic-gate /* 1017*0Sstevel@tonic-gate * "Unimport" the socket from SSL, i.e. get rid of the upper layer of 1018*0Sstevel@tonic-gate * the file descriptor stack, which represents SSL. 1019*0Sstevel@tonic-gate */ 1020*0Sstevel@tonic-gate soi.soinfo_prfd = sslfd; 1021*0Sstevel@tonic-gate sslfd = PR_PopIOLayer( soi.soinfo_prfd, PR_TOP_IO_LAYER ); 1022*0Sstevel@tonic-gate sslfd->dtor( sslfd ); 1023*0Sstevel@tonic-gate } 1024*0Sstevel@tonic-gate if ( NULL != ssoip ) { 1025*0Sstevel@tonic-gate ldapssl_free_socket_info( &ssoip ); 1026*0Sstevel@tonic-gate soi.soinfo_appdata = NULL; 1027*0Sstevel@tonic-gate } 1028*0Sstevel@tonic-gate prldap_set_default_socket_info( ld, &soi ); 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate return( -1 ); 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate /* 1035*0Sstevel@tonic-gate * Reset an LDAP session from SSL to a non-secure status. 1036*0Sstevel@tonic-gate * Basically, this function undoes the work done by ldapssl_install_routines. 1037*0Sstevel@tonic-gate */ 1038*0Sstevel@tonic-gate int ldapssl_reset_to_nonsecure ( LDAP *ld ) 1039*0Sstevel@tonic-gate { 1040*0Sstevel@tonic-gate PRLDAPSessionInfo sei; 1041*0Sstevel@tonic-gate LDAPSSLSessionInfo *sseip; 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate struct ldap_x_ext_io_fns iofns; 1044*0Sstevel@tonic-gate int rc = 0; 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate /* 1047*0Sstevel@tonic-gate * Retrieve session info. 1048*0Sstevel@tonic-gate */ 1049*0Sstevel@tonic-gate memset( &sei, 0, sizeof(sei)); 1050*0Sstevel@tonic-gate sei.seinfo_size = PRLDAP_SESSIONINFO_SIZE; 1051*0Sstevel@tonic-gate if ( prldap_get_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) { 1052*0Sstevel@tonic-gate return( -1 ); 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate sseip = (LDAPSSLSessionInfo *)sei.seinfo_appdata; 1055*0Sstevel@tonic-gate 1056*0Sstevel@tonic-gate if ( sseip != NULL ) { 1057*0Sstevel@tonic-gate /* 1058*0Sstevel@tonic-gate * Reset the standard extended io functions. 1059*0Sstevel@tonic-gate */ 1060*0Sstevel@tonic-gate memset( &iofns, 0, sizeof(iofns)); 1061*0Sstevel@tonic-gate iofns.lextiof_size = LDAP_X_EXTIO_FNS_SIZE; 1062*0Sstevel@tonic-gate if ( ldap_get_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) 1063*0Sstevel@tonic-gate < 0) { 1064*0Sstevel@tonic-gate rc = -1; 1065*0Sstevel@tonic-gate goto free_session_info; 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate 1068*0Sstevel@tonic-gate /* reset socket, connect, and ioctl */ 1069*0Sstevel@tonic-gate iofns.lextiof_connect = sseip->lssei_std_functions.lssf_connect_fn; 1070*0Sstevel@tonic-gate iofns.lextiof_close = sseip->lssei_std_functions.lssf_close_fn; 1071*0Sstevel@tonic-gate iofns.lextiof_disposehandle = 1072*0Sstevel@tonic-gate sseip->lssei_std_functions.lssf_disposehdl_fn; 1073*0Sstevel@tonic-gate 1074*0Sstevel@tonic-gate if ( ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, (void *)&iofns ) 1075*0Sstevel@tonic-gate < 0) { 1076*0Sstevel@tonic-gate rc = -1; 1077*0Sstevel@tonic-gate goto free_session_info; 1078*0Sstevel@tonic-gate } 1079*0Sstevel@tonic-gate 1080*0Sstevel@tonic-gate free_session_info: 1081*0Sstevel@tonic-gate ldapssl_free_session_info( &sseip ); 1082*0Sstevel@tonic-gate sei.seinfo_appdata = NULL; 1083*0Sstevel@tonic-gate if ( prldap_set_session_info( ld, NULL, &sei ) != LDAP_SUCCESS ) { 1084*0Sstevel@tonic-gate rc = -1; 1085*0Sstevel@tonic-gate } 1086*0Sstevel@tonic-gate } /* if ( sseip && *sseip ) */ 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate if ( ldap_set_option( ld, LDAP_OPT_SSL, LDAP_OPT_OFF ) < 0 ) { 1089*0Sstevel@tonic-gate return (-1); 1090*0Sstevel@tonic-gate } 1091*0Sstevel@tonic-gate 1092*0Sstevel@tonic-gate return rc; 1093*0Sstevel@tonic-gate } 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate 1096*0Sstevel@tonic-gate #ifdef _SOLARIS_SDK 1097*0Sstevel@tonic-gate static void 1098*0Sstevel@tonic-gate _nss_initf_ipnodes(nss_db_params_t *p) 1099*0Sstevel@tonic-gate { 1100*0Sstevel@tonic-gate static char *no_service = ""; 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate p->name = NSS_DBNAM_IPNODES; 1103*0Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 1104*0Sstevel@tonic-gate p->default_config = host_service == NULL ? no_service : host_service; 1105*0Sstevel@tonic-gate } 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate static void 1108*0Sstevel@tonic-gate _nss_initf_hosts(nss_db_params_t *p) 1109*0Sstevel@tonic-gate { 1110*0Sstevel@tonic-gate static char *no_service = ""; 1111*0Sstevel@tonic-gate 1112*0Sstevel@tonic-gate p->name = NSS_DBNAM_HOSTS; 1113*0Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 1114*0Sstevel@tonic-gate p->default_config = host_service == NULL ? no_service : host_service; 1115*0Sstevel@tonic-gate } 1116*0Sstevel@tonic-gate 1117*0Sstevel@tonic-gate static struct hostent * 1118*0Sstevel@tonic-gate _switch_gethostbyaddr_r(const char *addr, int len, int type, 1119*0Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen, 1120*0Sstevel@tonic-gate int *h_errnop) 1121*0Sstevel@tonic-gate { 1122*0Sstevel@tonic-gate nss_XbyY_args_t arg; 1123*0Sstevel@tonic-gate nss_status_t res; 1124*0Sstevel@tonic-gate int (*str2ent)(); 1125*0Sstevel@tonic-gate void (*nss_initf)(); 1126*0Sstevel@tonic-gate nss_db_root_t *nss_db_root; 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate if (AF_INET == type) { 1129*0Sstevel@tonic-gate str2ent = str2hostent; 1130*0Sstevel@tonic-gate nss_initf = _nss_initf_hosts; 1131*0Sstevel@tonic-gate nss_db_root = &db_root_hosts; 1132*0Sstevel@tonic-gate } else if (AF_INET6 == type) { 1133*0Sstevel@tonic-gate str2ent = str2hostent6; 1134*0Sstevel@tonic-gate nss_initf = _nss_initf_ipnodes; 1135*0Sstevel@tonic-gate nss_db_root = &db_root_ipnodes; 1136*0Sstevel@tonic-gate } else { 1137*0Sstevel@tonic-gate return NULL; 1138*0Sstevel@tonic-gate } 1139*0Sstevel@tonic-gate 1140*0Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2ent); 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate arg.key.hostaddr.addr = addr; 1143*0Sstevel@tonic-gate arg.key.hostaddr.len = len; 1144*0Sstevel@tonic-gate arg.key.hostaddr.type = type; 1145*0Sstevel@tonic-gate arg.stayopen = 0; 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate res = nss_search(nss_db_root, nss_initf, 1148*0Sstevel@tonic-gate NSS_DBOP_HOSTS_BYADDR, &arg); 1149*0Sstevel@tonic-gate arg.status = res; 1150*0Sstevel@tonic-gate *h_errnop = arg.h_errno; 1151*0Sstevel@tonic-gate return (struct hostent *)NSS_XbyY_FINI(&arg); 1152*0Sstevel@tonic-gate } 1153*0Sstevel@tonic-gate 1154*0Sstevel@tonic-gate /* 1155*0Sstevel@tonic-gate * ns_gethostbyaddr is used to be a substitute gethostbyaddr for 1156*0Sstevel@tonic-gate * libldap when ssl will need to determine the fully qualified 1157*0Sstevel@tonic-gate * host name from an address when it is unsafe to use the normal 1158*0Sstevel@tonic-gate * nameservice functions. 1159*0Sstevel@tonic-gate * 1160*0Sstevel@tonic-gate * Note that the ldap name service resolver calls this with the address as 1161*0Sstevel@tonic-gate * a character string - which we must convert into address form. 1162*0Sstevel@tonic-gate */ 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate /*ARGSUSED*/ 1165*0Sstevel@tonic-gate static LDAPHostEnt * 1166*0Sstevel@tonic-gate ns_gethostbyaddr(const char *addr, int len, int type, 1167*0Sstevel@tonic-gate LDAPHostEnt *result, char *buffer, int buflen, int *statusp, 1168*0Sstevel@tonic-gate void *extradata) 1169*0Sstevel@tonic-gate { 1170*0Sstevel@tonic-gate LDAPHostEnt *ldap_hent; 1171*0Sstevel@tonic-gate int h_errno; 1172*0Sstevel@tonic-gate struct hostent h_ent; 1173*0Sstevel@tonic-gate struct hostent *h_e = NULL; 1174*0Sstevel@tonic-gate struct in_addr a; 1175*0Sstevel@tonic-gate struct in6_addr a6; 1176*0Sstevel@tonic-gate int inet_error; /* error returned by inet_pton */ 1177*0Sstevel@tonic-gate 1178*0Sstevel@tonic-gate 1179*0Sstevel@tonic-gate if (addr == NULL || result == NULL || buffer == NULL || 1180*0Sstevel@tonic-gate (type != AF_INET && type != AF_INET6)) 1181*0Sstevel@tonic-gate return (NULL); 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate (void) memset(&h_ent, 0, sizeof (h_ent)); 1185*0Sstevel@tonic-gate 1186*0Sstevel@tonic-gate if (AF_INET == type) { 1187*0Sstevel@tonic-gate if (inet_pton(type, addr, &a.s_addr) == 1) { 1188*0Sstevel@tonic-gate h_e = _switch_gethostbyaddr_r((char *)&a, 1189*0Sstevel@tonic-gate sizeof (a.s_addr), type, &h_ent, 1190*0Sstevel@tonic-gate buffer, buflen, &h_errno); 1191*0Sstevel@tonic-gate } 1192*0Sstevel@tonic-gate } else if (AF_INET6 == type) { 1193*0Sstevel@tonic-gate if (inet_pton(type, addr, &a6.s6_addr) == 1) { 1194*0Sstevel@tonic-gate h_e = _switch_gethostbyaddr_r((char *)&a6, 1195*0Sstevel@tonic-gate sizeof (a6.s6_addr), type, &h_ent, 1196*0Sstevel@tonic-gate buffer, buflen, &h_errno); 1197*0Sstevel@tonic-gate } 1198*0Sstevel@tonic-gate } 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate if (h_e == NULL) { 1201*0Sstevel@tonic-gate ldap_hent = NULL; 1202*0Sstevel@tonic-gate } else { 1203*0Sstevel@tonic-gate (void) memset(result, 0, sizeof (LDAPHostEnt)); 1204*0Sstevel@tonic-gate ldap_hent = result; 1205*0Sstevel@tonic-gate result->ldaphe_name = h_e->h_name; 1206*0Sstevel@tonic-gate result->ldaphe_aliases = h_e->h_aliases; 1207*0Sstevel@tonic-gate result->ldaphe_addrtype = h_e->h_addrtype; 1208*0Sstevel@tonic-gate result->ldaphe_length = h_e->h_length; 1209*0Sstevel@tonic-gate result->ldaphe_addr_list = h_e->h_addr_list; 1210*0Sstevel@tonic-gate } 1211*0Sstevel@tonic-gate return (ldap_hent); 1212*0Sstevel@tonic-gate } 1213*0Sstevel@tonic-gate 1214*0Sstevel@tonic-gate /* 1215*0Sstevel@tonic-gate * ldapssl_install_gethostbyaddr attempts to prevent recursion in 1216*0Sstevel@tonic-gate * gethostbyaddr calls when an ip address is given to ssl. This ip address 1217*0Sstevel@tonic-gate * must be resolved to a host name. 1218*0Sstevel@tonic-gate * 1219*0Sstevel@tonic-gate * For example, libsldap cannot use LDAP to resolve this address to a 1220*0Sstevel@tonic-gate * name because of recursion. The caller is instructing libldap to skip 1221*0Sstevel@tonic-gate * the specified name service when resolving addresses for the specified 1222*0Sstevel@tonic-gate * ldap connection. 1223*0Sstevel@tonic-gate * 1224*0Sstevel@tonic-gate * Currently only ldap and dns name services always return fully qualified 1225*0Sstevel@tonic-gate * names. The other name services (files, nis, and nisplus) will returned 1226*0Sstevel@tonic-gate * fully qualified names if the host names are stored as fully qualified names 1227*0Sstevel@tonic-gate * in these name services. 1228*0Sstevel@tonic-gate * 1229*0Sstevel@tonic-gate * Note: 1230*0Sstevel@tonic-gate * 1231*0Sstevel@tonic-gate * Since host_service applies to all connections, calling 1232*0Sstevel@tonic-gate * ldapssl_install_gethostbyaddr with different name services to 1233*0Sstevel@tonic-gate * skip will lead to unpredictable results. 1234*0Sstevel@tonic-gate * 1235*0Sstevel@tonic-gate * Returns: 1236*0Sstevel@tonic-gate * 0 if success 1237*0Sstevel@tonic-gate * -1 if failure 1238*0Sstevel@tonic-gate */ 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate int 1241*0Sstevel@tonic-gate ldapssl_install_gethostbyaddr(LDAP *ld, const char *skip) 1242*0Sstevel@tonic-gate { 1243*0Sstevel@tonic-gate enum __nsw_parse_err pserr; 1244*0Sstevel@tonic-gate struct __nsw_switchconfig *conf; 1245*0Sstevel@tonic-gate struct __nsw_lookup *lkp; 1246*0Sstevel@tonic-gate struct ldap_dns_fns dns_fns; 1247*0Sstevel@tonic-gate char *name_list = NULL; 1248*0Sstevel@tonic-gate char *tmp; 1249*0Sstevel@tonic-gate const char *name; 1250*0Sstevel@tonic-gate int len; 1251*0Sstevel@tonic-gate boolean_t got_skip = B_FALSE; 1252*0Sstevel@tonic-gate 1253*0Sstevel@tonic-gate /* 1254*0Sstevel@tonic-gate * db_root_hosts.lock mutex is used to ensure that the name list 1255*0Sstevel@tonic-gate * is not in use by the name service switch while we are updating 1256*0Sstevel@tonic-gate * the host_service 1257*0Sstevel@tonic-gate */ 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate (void) mutex_lock(&db_root_hosts.lock); 1260*0Sstevel@tonic-gate conf = __nsw_getconfig("hosts", &pserr); 1261*0Sstevel@tonic-gate if (conf == NULL) { 1262*0Sstevel@tonic-gate (void) mutex_unlock(&db_root_hosts.lock); 1263*0Sstevel@tonic-gate return (0); 1264*0Sstevel@tonic-gate } 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate /* check for ldap and count other backends */ 1267*0Sstevel@tonic-gate for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 1268*0Sstevel@tonic-gate name = lkp->service_name; 1269*0Sstevel@tonic-gate if (strcmp(name, skip) == 0) { 1270*0Sstevel@tonic-gate got_skip = B_TRUE; 1271*0Sstevel@tonic-gate continue; 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate if (name_list == NULL) 1274*0Sstevel@tonic-gate name_list = strdup(name); 1275*0Sstevel@tonic-gate else { 1276*0Sstevel@tonic-gate len = strlen(name_list); 1277*0Sstevel@tonic-gate tmp = realloc(name_list, len + strlen(name) + 2); 1278*0Sstevel@tonic-gate if (tmp == NULL) { 1279*0Sstevel@tonic-gate free(name_list); 1280*0Sstevel@tonic-gate name_list = NULL; 1281*0Sstevel@tonic-gate } else { 1282*0Sstevel@tonic-gate name_list = tmp; 1283*0Sstevel@tonic-gate name_list[len++] = ' '; 1284*0Sstevel@tonic-gate (void) strcpy(name_list+len, name); 1285*0Sstevel@tonic-gate } 1286*0Sstevel@tonic-gate } 1287*0Sstevel@tonic-gate if (name_list == NULL) { /* alloc error */ 1288*0Sstevel@tonic-gate (void) mutex_unlock(&db_root_hosts.lock); 1289*0Sstevel@tonic-gate __nsw_freeconfig(conf); 1290*0Sstevel@tonic-gate return (-1); 1291*0Sstevel@tonic-gate } 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate __nsw_freeconfig(conf); 1294*0Sstevel@tonic-gate if (!got_skip) { 1295*0Sstevel@tonic-gate /* 1296*0Sstevel@tonic-gate * Since skip name service not used for hosts, we do not need 1297*0Sstevel@tonic-gate * to install our private address resolution function 1298*0Sstevel@tonic-gate */ 1299*0Sstevel@tonic-gate (void) mutex_unlock(&db_root_hosts.lock); 1300*0Sstevel@tonic-gate if (name_list != NULL) 1301*0Sstevel@tonic-gate free(name_list); 1302*0Sstevel@tonic-gate return (0); 1303*0Sstevel@tonic-gate } 1304*0Sstevel@tonic-gate if (host_service != NULL) 1305*0Sstevel@tonic-gate free(host_service); 1306*0Sstevel@tonic-gate host_service = name_list; 1307*0Sstevel@tonic-gate (void) mutex_unlock(&db_root_hosts.lock); 1308*0Sstevel@tonic-gate 1309*0Sstevel@tonic-gate if (ldap_get_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0) 1310*0Sstevel@tonic-gate return (-1); 1311*0Sstevel@tonic-gate dns_fns.lddnsfn_gethostbyaddr = ns_gethostbyaddr; 1312*0Sstevel@tonic-gate if (ldap_set_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0) 1313*0Sstevel@tonic-gate return (-1); 1314*0Sstevel@tonic-gate return (0); 1315*0Sstevel@tonic-gate } 1316*0Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 1317*0Sstevel@tonic-gate #endif /* NET_SSL */ 1318