1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 9 /* 10 * The contents of this file are subject to the Netscape Public 11 * License Version 1.1 (the "License"); you may not use this file 12 * except in compliance with the License. You may obtain a copy of 13 * the License at http://www.mozilla.org/NPL/ 14 * 15 * Software distributed under the License is distributed on an "AS 16 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 17 * implied. See the License for the specific language governing 18 * rights and limitations under the License. 19 * 20 * The Original Code is Mozilla Communicator client code, released 21 * March 31, 1998. 22 * 23 * The Initial Developer of the Original Code is Netscape 24 * Communications Corporation. Portions created by Netscape are 25 * Copyright (C) 1998-1999 Netscape Communications Corporation. All 26 * Rights Reserved. 27 * 28 * Contributor(s): 29 */ 30 31 /* 32 * DNS callback functions for libldap that use the NSPR (Netscape 33 * Portable Runtime) thread API. 34 * 35 */ 36 37 #ifdef _SOLARIS_SDK 38 #include "solaris-int.h" 39 #include <libintl.h> 40 #include <syslog.h> 41 #include <nsswitch.h> 42 #include <synch.h> 43 #include <nss_dbdefs.h> 44 #include <netinet/in.h> 45 static char *host_service = NULL; 46 static DEFINE_NSS_DB_ROOT(db_root_hosts); 47 #endif 48 49 #include "ldappr-int.h" 50 51 static LDAPHostEnt *prldap_gethostbyname( const char *name, 52 LDAPHostEnt *result, char *buffer, int buflen, int *statusp, 53 void *extradata ); 54 static LDAPHostEnt *prldap_gethostbyaddr( const char *addr, int length, 55 int type, LDAPHostEnt *result, char *buffer, int buflen, 56 int *statusp, void *extradata ); 57 static int prldap_getpeername( LDAP *ld, struct sockaddr *addr, 58 char *buffer, int buflen ); 59 static LDAPHostEnt *prldap_convert_hostent( LDAPHostEnt *ldhp, 60 PRHostEnt *prhp ); 61 62 #ifdef _SOLARIS_SDK 63 static LDAPHostEnt * 64 prldap_gethostbyname1(const char *name, LDAPHostEnt *result, 65 char *buffer, int buflen, int *statusp, void *extradata); 66 extern int 67 str2hostent(const char *instr, int lenstr, void *ent, char *buffer, 68 int buflen); 69 #endif /* _SOLARIS_SDK */ 70 71 72 /* 73 * Install NSPR DNS functions into ld (if ld is NULL, they are installed 74 * as the default functions for new LDAP * handles). 75 * 76 * Returns 0 if all goes well and -1 if not. 77 */ 78 int 79 prldap_install_dns_functions( LDAP *ld ) 80 { 81 struct ldap_dns_fns dnsfns; 82 83 memset( &dnsfns, '\0', sizeof(struct ldap_dns_fns) ); 84 dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE; 85 dnsfns.lddnsfn_gethostbyname = prldap_gethostbyname; 86 dnsfns.lddnsfn_gethostbyaddr = prldap_gethostbyaddr; 87 dnsfns.lddnsfn_getpeername = prldap_getpeername; 88 if ( ldap_set_option( ld, LDAP_OPT_DNS_FN_PTRS, (void *)&dnsfns ) != 0 ) { 89 return( -1 ); 90 } 91 92 return( 0 ); 93 } 94 95 96 static LDAPHostEnt * 97 prldap_gethostbyname( const char *name, LDAPHostEnt *result, 98 char *buffer, int buflen, int *statusp, void *extradata ) 99 { 100 PRHostEnt prhent; 101 102 if( !statusp || ( *statusp = (int)PR_GetIPNodeByName( name, 103 PRLDAP_DEFAULT_ADDRESS_FAMILY, PR_AI_DEFAULT, 104 buffer, buflen, &prhent )) == PR_FAILURE ) { 105 return( NULL ); 106 } 107 108 return( prldap_convert_hostent( result, &prhent )); 109 } 110 111 112 static LDAPHostEnt * 113 prldap_gethostbyaddr( const char *addr, int length, int type, 114 LDAPHostEnt *result, char *buffer, int buflen, int *statusp, 115 void *extradata ) 116 { 117 PRHostEnt prhent; 118 PRNetAddr iaddr; 119 120 if ( PR_SetNetAddr(PR_IpAddrNull, PRLDAP_DEFAULT_ADDRESS_FAMILY, 121 0, &iaddr) == PR_FAILURE 122 || PR_StringToNetAddr( addr, &iaddr ) == PR_FAILURE ) { 123 return( NULL ); 124 } 125 126 if( !statusp || (*statusp = PR_GetHostByAddr(&iaddr, buffer, 127 buflen, &prhent )) == PR_FAILURE ) { 128 return( NULL ); 129 } 130 return( prldap_convert_hostent( result, &prhent )); 131 } 132 133 static int 134 prldap_getpeername( LDAP *ld, struct sockaddr *addr, char *buffer, int buflen) 135 { 136 PRLDAPIOSocketArg *sa; 137 PRFileDesc *fd; 138 PRNetAddr iaddr; 139 int ret; 140 141 if (NULL != ld) { 142 ret = prldap_socket_arg_from_ld( ld, &sa ); 143 if (ret != LDAP_SUCCESS) { 144 return (-1); 145 } 146 ret = PR_GetPeerName(sa->prsock_prfd, &iaddr); 147 if( ret == PR_FAILURE ) { 148 return( -1 ); 149 } 150 *addr = *((struct sockaddr *)&iaddr.raw); 151 ret = PR_NetAddrToString(&iaddr, buffer, buflen); 152 if( ret == PR_FAILURE ) { 153 return( -1 ); 154 } 155 return (0); 156 } 157 return (-1); 158 } 159 160 161 /* 162 * Function: prldap_convert_hostent() 163 * Description: copy the fields of a PRHostEnt struct to an LDAPHostEnt 164 * Returns: the LDAPHostEnt pointer passed in. 165 */ 166 static LDAPHostEnt * 167 prldap_convert_hostent( LDAPHostEnt *ldhp, PRHostEnt *prhp ) 168 { 169 ldhp->ldaphe_name = prhp->h_name; 170 ldhp->ldaphe_aliases = prhp->h_aliases; 171 ldhp->ldaphe_addrtype = prhp->h_addrtype; 172 ldhp->ldaphe_length = prhp->h_length; 173 ldhp->ldaphe_addr_list = prhp->h_addr_list; 174 return( ldhp ); 175 } 176 177 #ifdef _SOLARIS_SDK 178 /* 179 * prldap_x_install_dns_skipdb attempts to prevent recursion in resolving 180 * the hostname to an IP address when a host name is given to LDAP user. 181 * 182 * For example, libsldap cannot use LDAP to resolve the host name to an 183 * address because of recursion. The caller is instructing libldap to skip 184 * the specified name service when resolving addresses for the specified 185 * ldap connection. 186 * 187 * Note: 188 * This only supports ipv4 addresses currently. 189 * 190 * Since host_service applies to all connections, calling 191 * prldap_x_install_dns_skipdb with name services other than 192 * ldap or what uses ldap (for example nis+ might use ldap) to 193 * skip will lead to unpredictable results. 194 * 195 * Returns: 196 * 0 if success and data base found 197 * -1 if failure 198 */ 199 200 int 201 prldap_x_install_dns_skipdb(LDAP *ld, const char *skip) 202 { 203 enum __nsw_parse_err pserr; 204 struct __nsw_switchconfig *conf; 205 struct __nsw_lookup *lkp; 206 struct ldap_dns_fns dns_fns; 207 char *name_list = NULL; 208 char *tmp; 209 const char *name; 210 int len; 211 boolean_t got_skip = B_FALSE; 212 213 /* 214 * db_root_hosts.lock mutex is used to ensure that the name list 215 * is not in use by the name service switch while we are updating 216 * the host_service 217 */ 218 219 (void) mutex_lock(&db_root_hosts.lock); 220 conf = __nsw_getconfig("hosts", &pserr); 221 if (conf == NULL) { 222 (void) mutex_unlock(&db_root_hosts.lock); 223 return (0); 224 } 225 226 /* check for skip and count other backends */ 227 for (lkp = conf->lookups; lkp != NULL; lkp = lkp->next) { 228 name = lkp->service_name; 229 if (strcmp(name, skip) == 0) { 230 got_skip = B_TRUE; 231 continue; 232 } 233 if (name_list == NULL) 234 name_list = strdup(name); 235 else { 236 len = strlen(name_list); 237 tmp = realloc(name_list, len + strlen(name) + 2); 238 if (tmp == NULL) { 239 free(name_list); 240 name_list = NULL; 241 } else { 242 name_list = tmp; 243 name_list[len++] = ' '; 244 (void) strcpy(name_list+len, name); 245 } 246 } 247 if (name_list == NULL) { /* alloc error */ 248 (void) mutex_unlock(&db_root_hosts.lock); 249 __nsw_freeconfig(conf); 250 return (-1); 251 } 252 } 253 __nsw_freeconfig(conf); 254 if (!got_skip) { 255 /* 256 * Since skip name service not used for hosts, we do not need 257 * to install our private address resolution function 258 */ 259 (void) mutex_unlock(&db_root_hosts.lock); 260 if (name_list != NULL) 261 free(name_list); 262 return (0); 263 } 264 if (host_service != NULL) 265 free(host_service); 266 host_service = name_list; 267 (void) mutex_unlock(&db_root_hosts.lock); 268 269 if (ldap_get_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0) 270 return (-1); 271 dns_fns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE; 272 dns_fns.lddnsfn_gethostbyname = prldap_gethostbyname1; 273 if (ldap_set_option(ld, LDAP_OPT_DNS_FN_PTRS, &dns_fns) != 0) 274 return (-1); 275 return (0); 276 } 277 278 /* 279 * prldap_initf_hosts is passed to and called by nss_search() as a 280 * service routine. 281 * 282 * Returns: 283 * None 284 */ 285 286 static void 287 prldap_initf_hosts(nss_db_params_t *p) 288 { 289 static char *no_service = ""; 290 291 p->name = NSS_DBNAM_HOSTS; 292 p->flags |= NSS_USE_DEFAULT_CONFIG; 293 p->default_config = host_service == NULL ? no_service : host_service; 294 } 295 296 /* 297 * called by prldap_gethostbyname1() 298 */ 299 /* 300 * prldap_switch_gethostbyname_r is called by prldap_gethostbyname1 as a 301 * substitute for gethostbyname_r(). A method which prevents recursion. see 302 * prldap_gethostbyname1() and prldap_x_install_dns_skipdb(). 303 * 304 * Returns: 305 * PR_SUCCESS if success 306 * PR_FAILURE if failure 307 */ 308 309 static int 310 prldap_switch_gethostbyname_r(const char *name, 311 struct hostent *result, char *buffer, int buflen, 312 int *h_errnop) 313 { 314 nss_XbyY_args_t arg; 315 nss_status_t res; 316 struct hostent *resp; 317 318 /* 319 * Log the information indicating that we are trying to 320 * resolve the LDAP server name. 321 */ 322 syslog(LOG_INFO, "libldap: Resolving server name \"%s\"", name); 323 324 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2hostent); 325 326 arg.key.name = name; 327 arg.stayopen = 0; 328 329 res = nss_search(&db_root_hosts, prldap_initf_hosts, 330 NSS_DBOP_HOSTS_BYNAME, &arg); 331 arg.status = res; 332 *h_errnop = arg.h_errno; 333 resp = (struct hostent *)NSS_XbyY_FINI(&arg); 334 335 return (resp != NULL ? PR_SUCCESS : PR_FAILURE); 336 } 337 338 /* 339 * prldap_gethostbyname1 is used to be a substitute gethostbyname_r for 340 * libldap when it is unsafe to use the normal nameservice functions. 341 * 342 * Returns: 343 * pointer to LDAPHostEnt: if success contains the address 344 * NULL pointer: if failure 345 */ 346 347 static LDAPHostEnt * 348 prldap_gethostbyname1(const char *name, LDAPHostEnt *result, 349 char *buffer, int buflen, int *statusp, void *extradata) 350 { 351 int h_errno; 352 LDAPHostEnt prhent; 353 354 memset(&prhent, '\0', sizeof (prhent)); 355 if (!statusp || ( *statusp = prldap_switch_gethostbyname_r(name, 356 &prhent, buffer, buflen, &h_errno )) == PR_FAILURE) { 357 /* 358 * If we got here, it means that we are not able to 359 * resolve the LDAP server name and so warn the system 360 * adminstrator accordingly. 361 */ 362 syslog(LOG_WARNING, "libldap: server name \"%s\" could not " 363 "be resolved", name); 364 return (NULL); 365 } 366 367 return (prldap_convert_hostent(result, &prhent)); 368 } 369 370 #endif /* _SOLARIS_SDK */ 371