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