gethostent.c revision 2830:5228d1267a01
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * gethostent.c
30 *
31 * In order to avoid duplicating libresolv code here, and since libresolv.so.2
32 * provides res_-equivalents of the getXbyY and {set,get}Xent, lets call
33 * re_gethostbyaddr() and so on from this file. Among other things, this
34 * should help us avoid problems like the one described in bug 1264386,
35 * where the internal getanswer() acquired new functionality in BIND 4.9.3,
36 * but the local copy of getanswer() in this file wasn't updated, so that new
37 * functionality wasn't available to the name service switch.
38 */
39
40#define	gethostbyaddr	res_gethostbyaddr
41#define	gethostbyname	res_gethostbyname
42#define	gethostbyname2	res_gethostbyname2
43#define	sethostent	res_sethostent
44#define	endhostent	res_endhostent
45
46#include "dns_common.h"
47
48extern char *inet_ntoa(struct in_addr in);
49
50struct hostent *_gethostbyname(int *h_errnop, const char *name);
51static struct hostent *_gethostbyaddr(int *h_errnop, const char *addr,
52    int len, int type);
53struct hostent *_nss_dns_gethostbyname2(int *h_errnop, const char *name);
54
55#pragma weak	res_gethostbyname
56#pragma weak	res_gethostbyname2
57#pragma weak	res_gethostbyaddr
58#pragma weak	res_sethostent
59#pragma weak	res_endhostent
60
61nss_backend_t *_nss_dns_constr(dns_backend_op_t ops[], int n_ops);
62nss_status_t __nss_dns_getbyaddr(dns_backend_ptr_t, void *);
63
64typedef union {
65	long al;
66	char ac;
67} align;
68
69/*
70 * Internet Name Domain Server (DNS) only implementation.
71 */
72static struct hostent *
73_gethostbyaddr(int *h_errnop, const char *addr, int len, int type)
74{
75	struct hostent	*hp;
76
77	hp = gethostbyaddr(addr, len, type);
78	*h_errnop = *get_h_errno();
79	return (hp);
80}
81
82struct hostent *
83_nss_dns_gethostbyname2(int *h_errnop, const char *name)
84{
85	struct hostent *hp;
86
87	hp = gethostbyname2(name, AF_INET6);
88	*h_errnop = *get_h_errno();
89	return (hp);
90}
91
92struct hostent *
93_gethostbyname(int *h_errnop, const char *name)
94{
95	struct hostent *hp;
96
97	hp = gethostbyname(name);
98	*h_errnop = *get_h_errno();
99	return (hp);
100}
101
102static void
103_sethostent(errp, stayopen)
104	nss_status_t	*errp;
105	int		stayopen;
106{
107	int	ret;
108
109	ret = sethostent(stayopen);
110	if (ret == 0)
111		*errp = NSS_SUCCESS;
112	else
113		*errp = NSS_UNAVAIL;
114}
115
116static void
117_endhostent(errp)
118	nss_status_t	*errp;
119{
120	int	ret;
121
122	ret = endhostent();
123	if (ret == 0)
124		*errp = NSS_SUCCESS;
125	else
126		*errp = NSS_UNAVAIL;
127}
128
129
130/*ARGSUSED*/
131static nss_status_t
132getbyname(be, a)
133	dns_backend_ptr_t	be;
134	void			*a;
135{
136	struct hostent	*he;
137	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
138	int		ret, mt_disabled;
139	int		old_retry;
140	sigset_t	oldmask;
141
142	switch_resolver_setup(&mt_disabled, &oldmask, &old_retry);
143
144	he = _gethostbyname(&argp->h_errno, argp->key.name);
145	if (he != NULL) {
146		if (argp->buf.result == NULL) {
147			/*
148			 * if asked to return data in string,
149			 * convert the hostent structure into
150			 * string data
151			 */
152			ret = ent2str(he, a, AF_INET);
153			if (ret == NSS_STR_PARSE_SUCCESS)
154				argp->returnval = argp->buf.buffer;
155		} else {
156			ret = ent2result(he, a, AF_INET);
157			if (ret == NSS_STR_PARSE_SUCCESS)
158				argp->returnval = argp->buf.result;
159		}
160
161		if (ret != NSS_STR_PARSE_SUCCESS) {
162			argp->h_errno = HOST_NOT_FOUND;
163			if (ret == NSS_STR_PARSE_ERANGE) {
164				argp->erange = 1;
165			}
166		}
167	}
168
169	switch_resolver_reset(mt_disabled, oldmask, old_retry);
170
171	return (_herrno2nss(argp->h_errno));
172}
173
174
175
176/*ARGSUSED*/
177static nss_status_t
178getbyaddr(be, a)
179	dns_backend_ptr_t	be;
180	void			*a;
181{
182	return (__nss_dns_getbyaddr(be, a));
183}
184
185
186/*
187 * Exposing a DNS backend specific interface so that it doesn't conflict
188 * with other getbyaddr() routines from other switch backends.
189 */
190/*ARGSUSED*/
191nss_status_t
192__nss_dns_getbyaddr(be, a)
193	dns_backend_ptr_t	be;
194	void			*a;
195{
196	size_t	n;
197	struct hostent	*he, *he2;
198	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
199	int		ret, save_h_errno, mt_disabled;
200	char		**ans, hbuf[MAXHOSTNAMELEN];
201	char		dst[INET6_ADDRSTRLEN];
202	struct in_addr	unmapv4;
203	sigset_t	oldmask;
204	int		af, addrlen;
205	void		*addrp;
206	int		old_retry;
207
208	switch_resolver_setup(&mt_disabled, &oldmask, &old_retry);
209
210	/* LINTED: E_BAD_PTR_CAST_ALIGN */
211	if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)argp->key.hostaddr.addr)) {
212		addrp = &unmapv4;
213		addrlen = sizeof (unmapv4);
214		af = AF_INET;
215		(void) memcpy(addrp, &argp->key.hostaddr.addr[12], addrlen);
216	} else {
217		addrp = (void *)argp->key.hostaddr.addr;
218		addrlen = argp->key.hostaddr.len;
219		af = argp->key.hostaddr.type;
220	}
221	he = _gethostbyaddr(&argp->h_errno, addrp, addrlen, af);
222
223	if (he != NULL) {
224		if (strlen(he->h_name) >= MAXHOSTNAMELEN)
225			ret = NSS_STR_PARSE_ERANGE;
226		else {
227			/* save a copy of the (alleged) hostname */
228			(void) strcpy(hbuf, he->h_name);
229			n = strlen(hbuf);
230			if (n < MAXHOSTNAMELEN-1 && hbuf[n-1] != '.') {
231				(void) strcat(hbuf, ".");
232			}
233
234			/*
235			 * if asked to return data in string,
236			 * convert the hostent structure into
237			 * string data
238			 */
239			if (argp->buf.result == NULL)
240				ret = ent2str(he, a, argp->key.hostaddr.type);
241			else
242				ret = ent2result(he, a,
243					argp->key.hostaddr.type);
244
245			save_h_errno = argp->h_errno;
246		}
247		if (ret == NSS_STR_PARSE_SUCCESS) {
248			/*
249			 * check to make sure by doing a forward query
250			 * We use _gethostbyname() to avoid the stack, and
251			 * then we throw the result from argp->h_errno away,
252			 * becase we don't care.  And besides you want the
253			 * return code from _gethostbyaddr() anyway.
254			 */
255
256			if (af == AF_INET)
257				he2 = _gethostbyname(&argp->h_errno, hbuf);
258			else
259				he2 = _nss_dns_gethostbyname2(&argp->h_errno,
260					hbuf);
261			if (he2 != (struct hostent *)NULL) {
262
263				/* until we prove name and addr match */
264				argp->h_errno = HOST_NOT_FOUND;
265				for (ans = he2->h_addr_list; *ans; ans++)
266					if (memcmp(*ans, addrp,	addrlen) ==
267						0) {
268					argp->h_errno = save_h_errno;
269					if (argp->buf.result == NULL)
270						argp->returnval =
271							argp->buf.buffer;
272					else
273						argp->returnval =
274							argp->buf.result;
275					break;
276						}
277			} else {
278
279				/*
280				 * What to do if _gethostbyname() fails ???
281				 * We assume they are doing something stupid
282				 * like registering addresses but not names
283				 * (some people actually think that provides
284				 * some "security", through obscurity).  So for
285				 * these poor lost souls, because we can't
286				 * PROVE spoofing and because we did try (and
287				 * we don't want a bug filed on this), we let
288				 * this go.  And return the name from byaddr.
289				 */
290				argp->h_errno = save_h_errno;
291				if (argp->buf.result == NULL)
292					argp->returnval = argp->buf.buffer;
293				else
294					argp->returnval = argp->buf.result;
295			}
296			/* we've been spoofed, make sure to log it. */
297			if (argp->h_errno == HOST_NOT_FOUND) {
298				if (argp->key.hostaddr.type == AF_INET)
299		syslog(LOG_NOTICE, "gethostbyaddr: %s != %s",
300		/* LINTED: E_BAD_PTR_CAST_ALIGN */
301		hbuf, inet_ntoa(*(struct in_addr *)argp->key.hostaddr.addr));
302				else
303		syslog(LOG_NOTICE, "gethostbyaddr: %s != %s",
304		hbuf, inet_ntop(AF_INET6, (void *) argp->key.hostaddr.addr,
305		dst, sizeof (dst)));
306			}
307		} else {
308			argp->h_errno = HOST_NOT_FOUND;
309			if (ret == NSS_STR_PARSE_ERANGE) {
310				argp->erange = 1;
311			}
312		}
313	}
314
315	switch_resolver_reset(mt_disabled, oldmask, old_retry);
316
317	return (_herrno2nss(argp->h_errno));
318}
319
320
321/*ARGSUSED*/
322static nss_status_t
323_nss_dns_getent(be, args)
324	dns_backend_ptr_t	be;
325	void			*args;
326{
327	return (NSS_UNAVAIL);
328}
329
330
331/*ARGSUSED*/
332static nss_status_t
333_nss_dns_setent(be, dummy)
334	dns_backend_ptr_t	be;
335	void			*dummy;
336{
337	nss_status_t	errp;
338
339	sigset_t	oldmask, newmask;
340	int		mt_disabled = 1;
341
342	/*
343	 * Try to enable MT; if not, we have to single-thread libresolv
344	 * access
345	 */
346	if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) {
347		(void) sigfillset(&newmask);
348		_thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
349		_mutex_lock(&one_lane);
350	}
351
352	_sethostent(&errp, 1);
353
354	if (mt_disabled) {
355		_mutex_unlock(&one_lane);
356		_thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
357	} else {
358		(void) (*disable_mt)();
359	}
360
361	return (errp);
362}
363
364
365/*ARGSUSED*/
366static nss_status_t
367_nss_dns_endent(be, dummy)
368	dns_backend_ptr_t	be;
369	void			*dummy;
370{
371	nss_status_t	errp;
372
373	sigset_t	oldmask, newmask;
374	int		mt_disabled = 1;
375
376	/*
377	 * Try to enable MT; if not, we have to single-thread libresolv
378	 * access
379	 */
380	if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) {
381		(void) sigfillset(&newmask);
382		_thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
383		_mutex_lock(&one_lane);
384	}
385
386	_endhostent(&errp);
387
388	if (mt_disabled) {
389		_mutex_unlock(&one_lane);
390		_thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
391	} else {
392		(void) (*disable_mt)();
393	}
394
395	return (errp);
396}
397
398
399/*ARGSUSED*/
400static nss_status_t
401_nss_dns_destr(be, dummy)
402	dns_backend_ptr_t	be;
403	void			*dummy;
404{
405	nss_status_t	errp;
406
407	if (be != 0) {
408		/* === Should change to invoke ops[ENDENT] ? */
409		sigset_t	oldmask, newmask;
410		int		mt_disabled = 1;
411
412		if (enable_mt == 0 || (mt_disabled = (*enable_mt)()) != 0) {
413			(void) sigfillset(&newmask);
414			_thr_sigsetmask(SIG_SETMASK, &newmask, &oldmask);
415			_mutex_lock(&one_lane);
416		}
417
418		_endhostent(&errp);
419
420		if (mt_disabled) {
421			_mutex_unlock(&one_lane);
422			_thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
423		} else {
424			(void) (*disable_mt)();
425		}
426
427		free(be);
428	}
429	return (NSS_SUCCESS);   /* In case anyone is dumb enough to check */
430}
431
432
433static dns_backend_op_t host_ops[] = {
434	_nss_dns_destr,
435	_nss_dns_endent,
436	_nss_dns_setent,
437	_nss_dns_getent,
438	getbyname,
439	getbyaddr,
440};
441
442/*ARGSUSED*/
443nss_backend_t *
444_nss_dns_hosts_constr(dummy1, dummy2, dummy3)
445	const char	*dummy1, *dummy2, *dummy3;
446{
447	return (_nss_dns_constr(host_ops,
448		sizeof (host_ops) / sizeof (host_ops[0])));
449}
450
451/*
452 * optional NSS2 packed backend gethostsbyname with ttl
453 * entry point.
454 *
455 * Returns:
456 *	NSS_SUCCESS - successful
457 *	NSS_NOTFOUND - successful but nothing found
458 *	NSS_ERROR - fallback to NSS backend lookup mode
459 * If successful, buffer will be filled with valid data
460 *
461 */
462
463/*ARGSUSED*/
464nss_status_t
465_nss_get_dns_hosts_name(dns_backend_ptr_t *be, void **bufp, size_t *sizep)
466{
467	return (_nss_dns_gethost_withttl(*bufp, *sizep, 0));
468}
469