10Sstevel@tonic-gate /* 2*441Ssdussud * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 70Sstevel@tonic-gate 80Sstevel@tonic-gate 90Sstevel@tonic-gate /* 100Sstevel@tonic-gate * The contents of this file are subject to the Netscape Public 110Sstevel@tonic-gate * License Version 1.1 (the "License"); you may not use this file 120Sstevel@tonic-gate * except in compliance with the License. You may obtain a copy of 130Sstevel@tonic-gate * the License at http://www.mozilla.org/NPL/ 140Sstevel@tonic-gate * 150Sstevel@tonic-gate * Software distributed under the License is distributed on an "AS 160Sstevel@tonic-gate * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 170Sstevel@tonic-gate * implied. See the License for the specific language governing 180Sstevel@tonic-gate * rights and limitations under the License. 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * The Original Code is Mozilla Communicator client code, released 210Sstevel@tonic-gate * March 31, 1998. 220Sstevel@tonic-gate * 230Sstevel@tonic-gate * The Initial Developer of the Original Code is Netscape 240Sstevel@tonic-gate * Communications Corporation. Portions created by Netscape are 250Sstevel@tonic-gate * Copyright (C) 1998-1999 Netscape Communications Corporation. All 260Sstevel@tonic-gate * Rights Reserved. 270Sstevel@tonic-gate * 280Sstevel@tonic-gate * Contributor(s): 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate /* 320Sstevel@tonic-gate * DNS callback functions for libldap that use the NSPR (Netscape 330Sstevel@tonic-gate * Portable Runtime) thread API. 340Sstevel@tonic-gate * 350Sstevel@tonic-gate */ 360Sstevel@tonic-gate 370Sstevel@tonic-gate #ifdef _SOLARIS_SDK 380Sstevel@tonic-gate #include "solaris-int.h" 390Sstevel@tonic-gate #include <libintl.h> 400Sstevel@tonic-gate #include <syslog.h> 410Sstevel@tonic-gate #include <nsswitch.h> 420Sstevel@tonic-gate #include <synch.h> 430Sstevel@tonic-gate #include <nss_dbdefs.h> 440Sstevel@tonic-gate #include <netinet/in.h> 450Sstevel@tonic-gate static char *host_service = NULL; 460Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root_hosts); 470Sstevel@tonic-gate #endif 480Sstevel@tonic-gate 490Sstevel@tonic-gate #include "ldappr-int.h" 500Sstevel@tonic-gate 510Sstevel@tonic-gate static LDAPHostEnt *prldap_gethostbyname( const char *name, 520Sstevel@tonic-gate LDAPHostEnt *result, char *buffer, int buflen, int *statusp, 530Sstevel@tonic-gate void *extradata ); 540Sstevel@tonic-gate static LDAPHostEnt *prldap_gethostbyaddr( const char *addr, int length, 550Sstevel@tonic-gate int type, LDAPHostEnt *result, char *buffer, int buflen, 560Sstevel@tonic-gate int *statusp, void *extradata ); 570Sstevel@tonic-gate static int prldap_getpeername( LDAP *ld, struct sockaddr *addr, 580Sstevel@tonic-gate char *buffer, int buflen ); 590Sstevel@tonic-gate static LDAPHostEnt *prldap_convert_hostent( LDAPHostEnt *ldhp, 600Sstevel@tonic-gate PRHostEnt *prhp ); 610Sstevel@tonic-gate 620Sstevel@tonic-gate #ifdef _SOLARIS_SDK 630Sstevel@tonic-gate static LDAPHostEnt * 640Sstevel@tonic-gate prldap_gethostbyname1(const char *name, LDAPHostEnt *result, 650Sstevel@tonic-gate char *buffer, int buflen, int *statusp, void *extradata); 660Sstevel@tonic-gate extern int 670Sstevel@tonic-gate str2hostent(const char *instr, int lenstr, void *ent, char *buffer, 680Sstevel@tonic-gate int buflen); 690Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 700Sstevel@tonic-gate 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * Install NSPR DNS functions into ld (if ld is NULL, they are installed 740Sstevel@tonic-gate * as the default functions for new LDAP * handles). 750Sstevel@tonic-gate * 760Sstevel@tonic-gate * Returns 0 if all goes well and -1 if not. 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate int 790Sstevel@tonic-gate prldap_install_dns_functions( LDAP *ld ) 800Sstevel@tonic-gate { 810Sstevel@tonic-gate struct ldap_dns_fns dnsfns; 820Sstevel@tonic-gate 830Sstevel@tonic-gate memset( &dnsfns, '\0', sizeof(struct ldap_dns_fns) ); 840Sstevel@tonic-gate dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE; 850Sstevel@tonic-gate dnsfns.lddnsfn_gethostbyname = prldap_gethostbyname; 860Sstevel@tonic-gate dnsfns.lddnsfn_gethostbyaddr = prldap_gethostbyaddr; 870Sstevel@tonic-gate dnsfns.lddnsfn_getpeername = prldap_getpeername; 880Sstevel@tonic-gate if ( ldap_set_option( ld, LDAP_OPT_DNS_FN_PTRS, (void *)&dnsfns ) != 0 ) { 890Sstevel@tonic-gate return( -1 ); 900Sstevel@tonic-gate } 910Sstevel@tonic-gate 920Sstevel@tonic-gate return( 0 ); 930Sstevel@tonic-gate } 940Sstevel@tonic-gate 950Sstevel@tonic-gate 960Sstevel@tonic-gate static LDAPHostEnt * 970Sstevel@tonic-gate prldap_gethostbyname( const char *name, LDAPHostEnt *result, 980Sstevel@tonic-gate char *buffer, int buflen, int *statusp, void *extradata ) 990Sstevel@tonic-gate { 1000Sstevel@tonic-gate PRHostEnt prhent; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate if( !statusp || ( *statusp = (int)PR_GetIPNodeByName( name, 1030Sstevel@tonic-gate PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT, 1040Sstevel@tonic-gate buffer, buflen, &prhent )) == PR_FAILURE ) { 1050Sstevel@tonic-gate return( NULL ); 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate return( prldap_convert_hostent( result, &prhent )); 1090Sstevel@tonic-gate } 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate static LDAPHostEnt * 1130Sstevel@tonic-gate prldap_gethostbyaddr( const char *addr, int length, int type, 1140Sstevel@tonic-gate LDAPHostEnt *result, char *buffer, int buflen, int *statusp, 1150Sstevel@tonic-gate void *extradata ) 1160Sstevel@tonic-gate { 1170Sstevel@tonic-gate PRHostEnt prhent; 1180Sstevel@tonic-gate PRNetAddr iaddr; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate if ( PR_SetNetAddr(PR_IpAddrNull, PRLDAP_DEFAULT_ADDRESS_FAMILY, 1210Sstevel@tonic-gate 0, &iaddr) == PR_FAILURE 1220Sstevel@tonic-gate || PR_StringToNetAddr( addr, &iaddr ) == PR_FAILURE ) { 1230Sstevel@tonic-gate return( NULL ); 1240Sstevel@tonic-gate } 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate if( !statusp || (*statusp = PR_GetHostByAddr(&iaddr, buffer, 1270Sstevel@tonic-gate buflen, &prhent )) == PR_FAILURE ) { 1280Sstevel@tonic-gate return( NULL ); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate return( prldap_convert_hostent( result, &prhent )); 1310Sstevel@tonic-gate } 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate static int 1340Sstevel@tonic-gate prldap_getpeername( LDAP *ld, struct sockaddr *addr, char *buffer, int buflen) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate PRLDAPIOSocketArg *sa; 1370Sstevel@tonic-gate PRFileDesc *fd; 1380Sstevel@tonic-gate PRNetAddr iaddr; 1390Sstevel@tonic-gate int ret; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate if (NULL != ld) { 1420Sstevel@tonic-gate ret = prldap_socket_arg_from_ld( ld, &sa ); 1430Sstevel@tonic-gate if (ret != LDAP_SUCCESS) { 1440Sstevel@tonic-gate return (-1); 1450Sstevel@tonic-gate } 1460Sstevel@tonic-gate ret = PR_GetPeerName(sa->prsock_prfd, &iaddr); 1470Sstevel@tonic-gate if( ret == PR_FAILURE ) { 1480Sstevel@tonic-gate return( -1 ); 1490Sstevel@tonic-gate } 1500Sstevel@tonic-gate *addr = *((struct sockaddr *)&iaddr.raw); 1510Sstevel@tonic-gate ret = PR_NetAddrToString(&iaddr, buffer, buflen); 1520Sstevel@tonic-gate if( ret == PR_FAILURE ) { 1530Sstevel@tonic-gate return( -1 ); 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate return (0); 1560Sstevel@tonic-gate } 1570Sstevel@tonic-gate return (-1); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* 1620Sstevel@tonic-gate * Function: prldap_convert_hostent() 1630Sstevel@tonic-gate * Description: copy the fields of a PRHostEnt struct to an LDAPHostEnt 1640Sstevel@tonic-gate * Returns: the LDAPHostEnt pointer passed in. 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate static LDAPHostEnt * 1670Sstevel@tonic-gate prldap_convert_hostent( LDAPHostEnt *ldhp, PRHostEnt *prhp ) 1680Sstevel@tonic-gate { 1690Sstevel@tonic-gate ldhp->ldaphe_name = prhp->h_name; 1700Sstevel@tonic-gate ldhp->ldaphe_aliases = prhp->h_aliases; 1710Sstevel@tonic-gate ldhp->ldaphe_addrtype = prhp->h_addrtype; 1720Sstevel@tonic-gate ldhp->ldaphe_length = prhp->h_length; 1730Sstevel@tonic-gate ldhp->ldaphe_addr_list = prhp->h_addr_list; 1740Sstevel@tonic-gate return( ldhp ); 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate #ifdef _SOLARIS_SDK 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * prldap_x_install_dns_skipdb attempts to prevent recursion in resolving 1800Sstevel@tonic-gate * the hostname to an IP address when a host name is given to LDAP user. 1810Sstevel@tonic-gate * 1820Sstevel@tonic-gate * For example, libsldap cannot use LDAP to resolve the host name to an 1830Sstevel@tonic-gate * address because of recursion. The caller is instructing libldap to skip 1840Sstevel@tonic-gate * the specified name service when resolving addresses for the specified 1850Sstevel@tonic-gate * ldap connection. 1860Sstevel@tonic-gate * 1870Sstevel@tonic-gate * Note: 1880Sstevel@tonic-gate * This only supports ipv4 addresses currently. 1890Sstevel@tonic-gate * 1900Sstevel@tonic-gate * Since host_service applies to all connections, calling 1910Sstevel@tonic-gate * prldap_x_install_dns_skipdb with name services other than 1920Sstevel@tonic-gate * ldap or what uses ldap (for example nis+ might use ldap) to 1930Sstevel@tonic-gate * skip will lead to unpredictable results. 1940Sstevel@tonic-gate * 1950Sstevel@tonic-gate * Returns: 1960Sstevel@tonic-gate * 0 if success and data base found 1970Sstevel@tonic-gate * -1 if failure 1980Sstevel@tonic-gate */ 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate int 2010Sstevel@tonic-gate prldap_x_install_dns_skipdb(LDAP *ld, const char *skip) 2020Sstevel@tonic-gate { 2030Sstevel@tonic-gate enum __nsw_parse_err pserr; 2040Sstevel@tonic-gate struct __nsw_switchconfig *conf; 2050Sstevel@tonic-gate struct __nsw_lookup *lkp; 2060Sstevel@tonic-gate struct ldap_dns_fns dns_fns; 2070Sstevel@tonic-gate char *name_list = NULL; 2080Sstevel@tonic-gate char *tmp; 2090Sstevel@tonic-gate const char *name; 2100Sstevel@tonic-gate int len; 2110Sstevel@tonic-gate boolean_t got_skip = B_FALSE; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * db_root_hosts.lock mutex is used to ensure that the name list 2150Sstevel@tonic-gate * is not in use by the name service switch while we are updating 2160Sstevel@tonic-gate * the host_service 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate (void) mutex_lock(&db_root_hosts.lock); 2200Sstevel@tonic-gate conf = __nsw_getconfig("hosts", &pserr); 2210Sstevel@tonic-gate if (conf == NULL) { 2220Sstevel@tonic-gate (void) mutex_unlock(&db_root_hosts.lock); 2230Sstevel@tonic-gate return (0); 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* check for skip and count other backends */ 2270Sstevel@tonic-gate for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 2280Sstevel@tonic-gate name = lkp->service_name; 2290Sstevel@tonic-gate if (strcmp(name, skip) == 0) { 2300Sstevel@tonic-gate got_skip = B_TRUE; 2310Sstevel@tonic-gate continue; 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate if (name_list == NULL) 2340Sstevel@tonic-gate name_list = strdup(name); 2350Sstevel@tonic-gate else { 2360Sstevel@tonic-gate len = strlen(name_list); 2370Sstevel@tonic-gate tmp = realloc(name_list, len + strlen(name) + 2); 2380Sstevel@tonic-gate if (tmp == NULL) { 2390Sstevel@tonic-gate free(name_list); 2400Sstevel@tonic-gate name_list = NULL; 2410Sstevel@tonic-gate } else { 2420Sstevel@tonic-gate name_list = tmp; 2430Sstevel@tonic-gate name_list[len++] = ' '; 2440Sstevel@tonic-gate (void) strcpy(name_list+len, name); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate if (name_list == NULL) { /* alloc error */ 2480Sstevel@tonic-gate (void) mutex_unlock(&db_root_hosts.lock); 2490Sstevel@tonic-gate __nsw_freeconfig(conf); 2500Sstevel@tonic-gate return (-1); 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate __nsw_freeconfig(conf); 2540Sstevel@tonic-gate if (!got_skip) { 2550Sstevel@tonic-gate /* 2560Sstevel@tonic-gate * Since skip name service not used for hosts, we do not need 2570Sstevel@tonic-gate * to install our private address resolution function 2580Sstevel@tonic-gate */ 2590Sstevel@tonic-gate (void) mutex_unlock(&db_root_hosts.lock); 2600Sstevel@tonic-gate if (name_list != NULL) 2610Sstevel@tonic-gate free(name_list); 2620Sstevel@tonic-gate return (0); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate if (host_service != NULL) 2650Sstevel@tonic-gate free(host_service); 2660Sstevel@tonic-gate host_service = name_list; 2670Sstevel@tonic-gate (void) mutex_unlock(&db_root_hosts.lock); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate if (ldap_get_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0) 2700Sstevel@tonic-gate return (-1); 2710Sstevel@tonic-gate dns_fns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE; 2720Sstevel@tonic-gate dns_fns.lddnsfn_gethostbyname = prldap_gethostbyname1; 2730Sstevel@tonic-gate if (ldap_set_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0) 2740Sstevel@tonic-gate return (-1); 2750Sstevel@tonic-gate return (0); 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate /* 2790Sstevel@tonic-gate * prldap_initf_hosts is passed to and called by nss_search() as a 2800Sstevel@tonic-gate * service routine. 2810Sstevel@tonic-gate * 2820Sstevel@tonic-gate * Returns: 2830Sstevel@tonic-gate * None 2840Sstevel@tonic-gate */ 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate static void 2870Sstevel@tonic-gate prldap_initf_hosts(nss_db_params_t *p) 2880Sstevel@tonic-gate { 2890Sstevel@tonic-gate static char *no_service = ""; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate p->name = NSS_DBNAM_HOSTS; 2920Sstevel@tonic-gate p->flags |= NSS_USE_DEFAULT_CONFIG; 2930Sstevel@tonic-gate p->default_config = host_service == NULL ? no_service : host_service; 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /* 2970Sstevel@tonic-gate * called by prldap_gethostbyname1() 2980Sstevel@tonic-gate */ 2990Sstevel@tonic-gate /* 3000Sstevel@tonic-gate * prldap_switch_gethostbyname_r is called by prldap_gethostbyname1 as a 3010Sstevel@tonic-gate * substitute for gethostbyname_r(). A method which prevents recursion. see 3020Sstevel@tonic-gate * prldap_gethostbyname1() and prldap_x_install_dns_skipdb(). 3030Sstevel@tonic-gate * 3040Sstevel@tonic-gate * Returns: 305*441Ssdussud * PR_SUCCESS if success 3060Sstevel@tonic-gate * PR_FAILURE if failure 3070Sstevel@tonic-gate */ 3080Sstevel@tonic-gate 309*441Ssdussud static int 3100Sstevel@tonic-gate prldap_switch_gethostbyname_r(const char *name, 3110Sstevel@tonic-gate struct hostent *result, char *buffer, int buflen, 3120Sstevel@tonic-gate int *h_errnop) 3130Sstevel@tonic-gate { 3140Sstevel@tonic-gate nss_XbyY_args_t arg; 3150Sstevel@tonic-gate nss_status_t res; 316*441Ssdussud struct hostent *resp; 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate /* 3190Sstevel@tonic-gate * Log the information indicating that we are trying to 3200Sstevel@tonic-gate * resolve the LDAP server name. 3210Sstevel@tonic-gate */ 3220Sstevel@tonic-gate syslog(LOG_INFO, "libldap: Resolving server name \"%s\"", name); 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 3250Sstevel@tonic-gate 3260Sstevel@tonic-gate arg.key.name = name; 3270Sstevel@tonic-gate arg.stayopen = 0; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate res = nss_search(&db_root_hosts, prldap_initf_hosts, 3300Sstevel@tonic-gate NSS_DBOP_HOSTS_BYNAME, &arg); 3310Sstevel@tonic-gate arg.status = res; 3320Sstevel@tonic-gate *h_errnop = arg.h_errno; 333*441Ssdussud resp = (struct hostent *)NSS_XbyY_FINI(&arg); 334*441Ssdussud 335*441Ssdussud return (resp != NULL ? PR_SUCCESS : PR_FAILURE); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * prldap_gethostbyname1 is used to be a substitute gethostbyname_r for 3400Sstevel@tonic-gate * libldap when it is unsafe to use the normal nameservice functions. 3410Sstevel@tonic-gate * 3420Sstevel@tonic-gate * Returns: 3430Sstevel@tonic-gate * pointer to LDAPHostEnt: if success contains the address 3440Sstevel@tonic-gate * NULL pointer: if failure 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate static LDAPHostEnt * 3480Sstevel@tonic-gate prldap_gethostbyname1(const char *name, LDAPHostEnt *result, 3490Sstevel@tonic-gate char *buffer, int buflen, int *statusp, void *extradata) 3500Sstevel@tonic-gate { 3510Sstevel@tonic-gate int h_errno; 3520Sstevel@tonic-gate LDAPHostEnt prhent; 3530Sstevel@tonic-gate 354*441Ssdussud memset(&prhent, '\0', sizeof (prhent)); 3550Sstevel@tonic-gate if (!statusp || ( *statusp = prldap_switch_gethostbyname_r(name, 3560Sstevel@tonic-gate &prhent, buffer, buflen, &h_errno )) == PR_FAILURE) { 3570Sstevel@tonic-gate /* 3580Sstevel@tonic-gate * If we got here, it means that we are not able to 3590Sstevel@tonic-gate * resolve the LDAP server name and so warn the system 3600Sstevel@tonic-gate * adminstrator accordingly. 3610Sstevel@tonic-gate */ 3620Sstevel@tonic-gate syslog(LOG_WARNING, "libldap: server name \"%s\" could not " 3630Sstevel@tonic-gate "be resolved", name); 3640Sstevel@tonic-gate return (NULL); 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate 3670Sstevel@tonic-gate return (prldap_convert_hostent(result, &prhent)); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate #endif /* _SOLARIS_SDK */ 371