Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / lib / nsswitch / dns / common / dns_mt.c
blob128b1bde759c47bbbb014d7bd9e6e06f1f8e6f76
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * dns_mt.c
32 * This file contains all the MT related routines for the DNS backend.
35 #include "dns_common.h"
36 #include <dlfcn.h>
39 * If the DNS name service switch routines are used in a binary that depends
40 * on an older libresolv (libresolv.so.1, say), then having nss_dns.so.1 or
41 * libnss_dns.a depend on a newer libresolv (libresolv.so.2) will cause
42 * relocation problems. In particular, copy relocation of the _res structure
43 * (which changes in size from libresolv.so.1 to libresolv.so.2) could
44 * cause corruption, and result in a number of strange problems, including
45 * core dumps. Hence, we check if a libresolv is already loaded.
48 #pragma init(_nss_dns_init)
49 static void _nss_dns_init(void);
51 extern struct hostent *res_gethostbyname(const char *);
52 #pragma weak res_gethostbyname
54 #define RES_SET_NO_HOSTS_FALLBACK "__res_set_no_hosts_fallback"
55 extern void __res_set_no_hosts_fallback(void);
56 #pragma weak __res_set_no_hosts_fallback
58 #define RES_UNSET_NO_HOSTS_FALLBACK "__res_unset_no_hosts_fallback"
59 extern void __res_unset_no_hosts_fallback(void);
60 #pragma weak __res_unset_no_hosts_fallback
62 #define RES_GET_RES "__res_get_res"
63 extern struct __res_state *__res_get_res(void);
64 #pragma weak __res_get_res
66 #define RES_ENABLE_MT "__res_enable_mt"
67 extern int __res_enable_mt(void);
68 #pragma weak __res_enable_mt
70 #define RES_DISABLE_MT "__res_disable_mt"
71 extern int __res_disable_mt(void);
72 #pragma weak __res_disable_mt
74 #define RES_GET_H_ERRNO "__res_get_h_errno"
75 extern int *__res_get_h_errno();
76 #pragma weak __res_get_h_errno
78 #define __H_ERRNO "__h_errno"
79 extern int *__h_errno(void);
80 #pragma weak __h_errno
82 #define RES_OVERRIDE_RETRY "__res_override_retry"
83 extern int __res_override_retry(int);
84 #pragma weak __res_override_retry
86 static void __fallback_set_no_hosts(void);
87 static int *__fallback_h_errno(void);
88 static int __fallback_override_retry(int);
89 static int __is_mt_safe(void);
91 void (*set_no_hosts_fallback)(void) = __fallback_set_no_hosts;
92 void (*unset_no_hosts_fallback)(void) = __fallback_set_no_hosts;
93 struct __res_state *(*set_res_retry)() = 0;
94 int (*enable_mt)() = 0;
95 int (*disable_mt)() = 0;
96 int *(*get_h_errno)(void) = 0;
97 int (*override_retry)(int) = 0;
99 /* Usually set from the Makefile */
100 #ifndef NSS_DNS_LIBRESOLV
101 #define NSS_DNS_LIBRESOLV "libresolv.so.2"
102 #endif
104 /* From libresolv */
105 extern int h_errno;
107 mutex_t one_lane = DEFAULTMUTEX;
109 void
110 _nss_dns_init(void)
112 void *reslib, (*f_void_ptr)();
114 /* If no libresolv library, then load one */
115 if (res_gethostbyname == 0) {
116 if ((reslib =
117 dlopen(NSS_DNS_LIBRESOLV, RTLD_LAZY|RTLD_GLOBAL)) != 0) {
118 /* Turn off /etc/hosts fall back in libresolv */
119 if ((f_void_ptr = (void (*)(void))dlsym(reslib,
120 RES_SET_NO_HOSTS_FALLBACK)) != 0) {
121 set_no_hosts_fallback = f_void_ptr;
123 if ((f_void_ptr = (void (*)(void))dlsym(reslib,
124 RES_SET_NO_HOSTS_FALLBACK)) != 0) {
125 unset_no_hosts_fallback = f_void_ptr;
127 /* Set number of resolver retries */
128 if ((override_retry = (int (*)(int))dlsym(reslib,
129 RES_OVERRIDE_RETRY)) == 0) {
130 set_res_retry =
131 (struct __res_state *(*)(void))dlsym(reslib,
132 RES_GET_RES);
133 override_retry = __fallback_override_retry;
136 * Select h_errno retrieval function. A BIND 8.2.2
137 * libresolv.so.2 will have __h_errno, a BIND 8.1.2
138 * one will have __res_get_h_errno, and other
139 * versions may have nothing at all.
141 * Also try to bind to the relevant MT enable/disable
142 * functions which are also dependent on the version
143 * of the BIND libresolv.so.2 being used.
145 if ((get_h_errno = (int *(*)(void))dlsym(reslib,
146 __H_ERRNO)) != 0) {
147 /* BIND 8.2.2 libresolv.so.2 is MT safe. */
148 enable_mt = __is_mt_safe;
149 disable_mt = __is_mt_safe;
150 } else {
151 if ((get_h_errno =
152 (int *(*)(void))dlsym(reslib,
153 RES_GET_H_ERRNO)) == 0) {
154 get_h_errno = __fallback_h_errno;
157 * Pre-BIND 8.2.2 was not MT safe. Try to
158 * bind the MT enable/disable functions.
160 if ((enable_mt = (int (*)(void))dlsym(reslib,
161 RES_ENABLE_MT)) != 0 &&
162 (disable_mt = (int (*)(void))dlsym(reslib,
163 RES_DISABLE_MT)) == 0) {
164 enable_mt = 0;
168 } else {
169 /* Libresolv already loaded */
170 if ((f_void_ptr = __res_set_no_hosts_fallback) != 0) {
171 set_no_hosts_fallback = f_void_ptr;
173 if ((f_void_ptr = __res_unset_no_hosts_fallback) != 0) {
174 unset_no_hosts_fallback = f_void_ptr;
176 if ((override_retry = __res_override_retry) == 0) {
177 set_res_retry = __res_get_res;
178 override_retry = __fallback_override_retry;
180 if ((get_h_errno = __h_errno) == 0 &&
181 (get_h_errno = __res_get_h_errno) == 0) {
182 get_h_errno = __fallback_h_errno;
184 if (get_h_errno == __h_errno) {
185 enable_mt = __is_mt_safe;
186 disable_mt = __is_mt_safe;
187 } else {
188 if ((enable_mt = __res_enable_mt) != 0 &&
189 (disable_mt = __res_disable_mt) == 0) {
190 enable_mt = 0;
199 * Integration of BIND 8.1.2 introduced two new Sun private functions,
200 * __res_enable_mt() and __res_disable_mt(), that enabled and disabled
201 * MT mode per-thread. These functions are in the private libresolv.so.2
202 * interface, and intended for use by nss_dns.so.1.
204 * BIND 8.2.2 removed the need for those two functions. As similar
205 * functionality was provided in BIND further up the stack. However the
206 * functions remain to satisfy any application that directly called upon
207 * them. Only, __res_enable_mt() was modified to return failure.
208 * Indicated by a non-zero return value. So that those unconventional
209 * applications would not then presume that res_send() and friends are
210 * MT-safe, when in fact they are not.
212 * To prevent nss_dns from locking inappropriately __is_mt_safe() is
213 * called in place of __res_enable_mt() and __res_disable_mt() if BIND
214 * 8.2.2 libresolv.so.2 being used. __is_mt_safe() returns success
215 * indicated by a return code of zero. Signifying that no locking is
216 * necessary.
218 * MT applications making calls to gethostby*_r() or getipnodeby*()
219 * linked to libresolv.so.1 or linked statically with pre-BIND 8.2.2
220 * libresolv.a, doubtful as we don't ship a static version, would require
221 * locking within the nsswitch back-end. Hence the mechanism can not
222 * simply be removed.
225 static int
226 __is_mt_safe(void) {
227 return (0);
232 * Return pointer to the global h_errno variable
234 static int *
235 __fallback_h_errno(void) {
236 return (&h_errno);
241 * This function is called when the resolver library doesn't provide its
242 * own function to establish an override retry. If we can get a pointer
243 * to the per-thread _res (i.e., set_res_retry != 0), we set the retries
244 * directly, and return the previous number of retries. Otherwise, there's
245 * nothing to do.
247 static int
248 __fallback_override_retry(int retry) {
249 struct __res_state *res;
250 int old_retry = 0;
252 if (set_res_retry != 0) {
253 res = set_res_retry();
254 old_retry = res->retry;
255 res->retry = retry;
257 return (old_retry);
261 static void
262 __fallback_set_no_hosts(void) {
267 * Common code to enable/disable MT mode, set/unset no-/etc/hosts fallback,
268 * and to set the number of retries.
270 void
271 switch_resolver_setup(int *mt_disabled, sigset_t *oldmask, int *old_retry) {
274 * Try to enable MT mode. If that isn't possible, mask signals,
275 * and mutex_lock.
277 *mt_disabled = 1;
278 if (enable_mt == 0 || (*mt_disabled = (*enable_mt)()) != 0) {
279 sigset_t newmask;
280 (void) sigfillset(&newmask);
281 (void) thr_sigsetmask(SIG_SETMASK, &newmask, oldmask);
282 (void) mutex_lock(&one_lane);
286 * Disable any fallback to /etc/hosts (or /etc/inet/ipnodes, when
287 * libresolv knows about that file).
289 (*set_no_hosts_fallback)();
292 * The NS switch wants to handle retries on its own.
294 *old_retry = (*override_retry)(1);
298 void
299 switch_resolver_reset(int mt_disabled, sigset_t oldmask, int old_retry) {
301 if (mt_disabled) {
302 (void) mutex_unlock(&one_lane);
303 (void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
304 } else {
305 (void) (*disable_mt)();
308 (*unset_no_hosts_fallback)();
310 (void) (*override_retry)(old_retry);