8ba1e9938701db48755138140984ca4e251b7cf6
[platform/upstream/glibc.git] / nss / getXXbyYY_r.c
1 /* Copyright (C) 1996-2012 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <assert.h>
20 #include <atomic.h>
21 #include <errno.h>
22 #include <stdbool.h>
23 #include "nsswitch.h"
24 #include "sysdep.h"
25 #ifdef USE_NSCD
26 # include <nscd/nscd_proto.h>
27 #endif
28 #ifdef NEED__RES_HCONF
29 # include <resolv/res_hconf.h>
30 #endif
31 #ifdef NEED__RES
32 # include <resolv.h>
33 #endif
34 /*******************************************************************\
35 |* Here we assume several symbols to be defined:                   *|
36 |*                                                                 *|
37 |* LOOKUP_TYPE   - the return type of the function                 *|
38 |*                                                                 *|
39 |* FUNCTION_NAME - name of the non-reentrant function              *|
40 |*                                                                 *|
41 |* DATABASE_NAME - name of the database the function accesses      *|
42 |*                 (e.g., host, services, ...)                     *|
43 |*                                                                 *|
44 |* ADD_PARAMS    - additional parameters, can vary in number       *|
45 |*                                                                 *|
46 |* ADD_VARIABLES - names of additional parameters                  *|
47 |*                                                                 *|
48 |* Optionally the following vars can be defined:                   *|
49 |*                                                                 *|
50 |* EXTRA_PARAMS  - optional parameters, can vary in number         *|
51 |*                                                                 *|
52 |* EXTRA_VARIABLES - names of optional parameter                   *|
53 |*                                                                 *|
54 |* FUNCTION_NAME - alternative name of the non-reentrant function  *|
55 |*                                                                 *|
56 |* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
57 |*                 the global `h_errno' variable.                  *|
58 |*                                                                 *|
59 |* NEED__RES     - the global _res variable might be used so we    *|
60 |*                 will have to initialize it if necessary         *|
61 |*                                                                 *|
62 |* PREPROCESS    - code run before anything else                   *|
63 |*                                                                 *|
64 |* POSTPROCESS   - code run after the lookup                       *|
65 |*                                                                 *|
66 \*******************************************************************/
67
68 /* To make the real sources a bit prettier.  */
69 #define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
70 #ifdef FUNCTION2_NAME
71 # define REENTRANT2_NAME APPEND_R (FUNCTION2_NAME)
72 #else
73 # define REENTRANT2_NAME NULL
74 #endif
75 #define APPEND_R(name) APPEND_R1 (name)
76 #define APPEND_R1(name) name##_r
77 #define INTERNAL(name) INTERNAL1 (name)
78 #define INTERNAL1(name) __##name
79 #define NEW(name) NEW1 (name)
80 #define NEW1(name) __new_##name
81
82 #ifdef USE_NSCD
83 # define NSCD_NAME ADD_NSCD (REENTRANT_NAME)
84 # define ADD_NSCD(name) ADD_NSCD1 (name)
85 # define ADD_NSCD1(name) __nscd_##name
86 # define NOT_USENSCD_NAME ADD_NOT_NSCDUSE (DATABASE_NAME)
87 # define ADD_NOT_NSCDUSE(name) ADD_NOT_NSCDUSE1 (name)
88 # define ADD_NOT_NSCDUSE1(name) __nss_not_use_nscd_##name
89 # define CONCAT2(arg1, arg2) CONCAT2_2 (arg1, arg2)
90 # define CONCAT2_2(arg1, arg2) arg1##arg2
91 #endif
92
93 #define FUNCTION_NAME_STRING STRINGIZE (FUNCTION_NAME)
94 #define REENTRANT_NAME_STRING STRINGIZE (REENTRANT_NAME)
95 #ifdef FUNCTION2_NAME
96 # define REENTRANT2_NAME_STRING STRINGIZE (REENTRANT2_NAME)
97 #else
98 # define REENTRANT2_NAME_STRING NULL
99 #endif
100 #define DATABASE_NAME_STRING STRINGIZE (DATABASE_NAME)
101 #define STRINGIZE(name) STRINGIZE1 (name)
102 #define STRINGIZE1(name) #name
103
104 #ifndef DB_LOOKUP_FCT
105 # define DB_LOOKUP_FCT CONCAT3_1 (__nss_, DATABASE_NAME, _lookup2)
106 # define CONCAT3_1(Pre, Name, Post) CONCAT3_2 (Pre, Name, Post)
107 # define CONCAT3_2(Pre, Name, Post) Pre##Name##Post
108 #endif
109
110 /* Sometimes we need to store error codes in the `h_errno' variable.  */
111 #ifdef NEED_H_ERRNO
112 # define H_ERRNO_PARM , int *h_errnop
113 # define H_ERRNO_VAR , h_errnop
114 # define H_ERRNO_VAR_P h_errnop
115 #else
116 # define H_ERRNO_PARM
117 # define H_ERRNO_VAR
118 # define H_ERRNO_VAR_P NULL
119 #endif
120
121 #ifndef EXTRA_PARAMS
122 # define EXTRA_PARAMS
123 #endif
124 #ifndef EXTRA_VARIABLES
125 # define EXTRA_VARIABLES
126 #endif
127
128 #ifdef HAVE_AF
129 # define AF_VAL af
130 #else
131 # define AF_VAL AF_INET
132 #endif
133
134 /* Type of the lookup function we need here.  */
135 typedef enum nss_status (*lookup_function) (ADD_PARAMS, LOOKUP_TYPE *, char *,
136                                             size_t, int * H_ERRNO_PARM
137                                             EXTRA_PARAMS);
138
139 /* The lookup function for the first entry of this service.  */
140 extern int DB_LOOKUP_FCT (service_user **nip, const char *name,
141                           const char *name2, void **fctp)
142      internal_function;
143 libc_hidden_proto (DB_LOOKUP_FCT)
144
145
146 int
147 INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
148                            size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM
149                            EXTRA_PARAMS)
150 {
151   static bool startp_initialized;
152   static service_user *startp;
153   static lookup_function start_fct;
154   service_user *nip;
155   union
156   {
157     lookup_function l;
158     void *ptr;
159   } fct;
160
161   int no_more;
162   enum nss_status status = NSS_STATUS_UNAVAIL;
163 #ifdef USE_NSCD
164   int nscd_status;
165 #endif
166 #ifdef NEED_H_ERRNO
167   bool any_service = false;
168 #endif
169
170 #ifdef PREPROCESS
171   PREPROCESS;
172 #endif
173
174 #ifdef HANDLE_DIGITS_DOTS
175   switch (__nss_hostname_digits_dots (name, resbuf, &buffer, NULL,
176                                       buflen, result, &status, AF_VAL,
177                                       H_ERRNO_VAR_P))
178     {
179     case -1:
180       return errno;
181     case 1:
182       goto done;
183     }
184 #endif
185
186 #ifdef USE_NSCD
187   if (NOT_USENSCD_NAME > 0 && ++NOT_USENSCD_NAME > NSS_NSCD_RETRY)
188     NOT_USENSCD_NAME = 0;
189
190   if (!NOT_USENSCD_NAME
191       && !__nss_database_custom[CONCAT2 (NSS_DBSIDX_, DATABASE_NAME)])
192     {
193       nscd_status = NSCD_NAME (ADD_VARIABLES, resbuf, buffer, buflen, result
194                                H_ERRNO_VAR);
195       if (nscd_status >= 0)
196         return nscd_status;
197     }
198 #endif
199
200   if (! startp_initialized)
201     {
202       no_more = DB_LOOKUP_FCT (&nip, REENTRANT_NAME_STRING,
203                                REENTRANT2_NAME_STRING, &fct.ptr);
204       if (no_more)
205         {
206           void *tmp_ptr = (service_user *) -1l;
207 #ifdef PTR_MANGLE
208           PTR_MANGLE (tmp_ptr);
209 #endif
210           startp = tmp_ptr;
211         }
212       else
213         {
214 #ifdef NEED__RES
215           /* The resolver code will really be used so we have to
216              initialize it.  */
217           if (__res_maybe_init (&_res, 0) == -1)
218             {
219               *h_errnop = NETDB_INTERNAL;
220               *result = NULL;
221               return errno;
222             }
223 #endif /* need _res */
224 #ifdef NEED__RES_HCONF
225           if (!_res_hconf.initialized)
226             _res_hconf_init ();
227 #endif /* need _res_hconf */
228
229           void *tmp_ptr = fct.l;
230 #ifdef PTR_MANGLE
231           PTR_MANGLE (tmp_ptr);
232 #endif
233           start_fct = tmp_ptr;
234           tmp_ptr = nip;
235 #ifdef PTR_MANGLE
236           PTR_MANGLE (tmp_ptr);
237 #endif
238           startp = tmp_ptr;
239         }
240
241       /* Make sure start_fct and startp are written before
242          startp_initialized.  */
243       atomic_write_barrier ();
244       startp_initialized = true;
245     }
246   else
247     {
248       fct.l = start_fct;
249       nip = startp;
250 #ifdef PTR_DEMANGLE
251       PTR_DEMANGLE (fct.l);
252       PTR_DEMANGLE (nip);
253 #endif
254       no_more = nip == (service_user *) -1l;
255     }
256
257   while (no_more == 0)
258     {
259 #ifdef NEED_H_ERRNO
260       any_service = true;
261 #endif
262
263       status = DL_CALL_FCT (fct.l, (ADD_VARIABLES, resbuf, buffer, buflen,
264                                     &errno H_ERRNO_VAR EXTRA_VARIABLES));
265
266       /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
267          provided buffer is too small.  In this case we should give
268          the user the possibility to enlarge the buffer and we should
269          not simply go on with the next service (even if the TRYAGAIN
270          action tells us so).  */
271       if (status == NSS_STATUS_TRYAGAIN
272 #ifdef NEED_H_ERRNO
273           && *h_errnop == NETDB_INTERNAL
274 #endif
275           && errno == ERANGE)
276         break;
277
278       no_more = __nss_next2 (&nip, REENTRANT_NAME_STRING,
279                              REENTRANT2_NAME_STRING, &fct.ptr, status, 0);
280     }
281
282 #ifdef HANDLE_DIGITS_DOTS
283 done:
284 #endif
285   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
286 #ifdef NEED_H_ERRNO
287   if (status != NSS_STATUS_SUCCESS && ! any_service)
288     /* We were not able to use any service.  */
289     *h_errnop = NO_RECOVERY;
290 #endif
291 #ifdef POSTPROCESS
292   POSTPROCESS;
293 #endif
294
295   int res;
296   if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
297     res = 0;
298   /* Don't pass back ERANGE if this is not for a too-small buffer.  */
299   else if (errno == ERANGE && status != NSS_STATUS_TRYAGAIN)
300     res = EINVAL;
301 #ifdef NEED_H_ERRNO
302   /* These functions only set errno if h_errno is NETDB_INTERNAL.  */
303   else if (status == NSS_STATUS_TRYAGAIN && *h_errnop != NETDB_INTERNAL)
304     res = EAGAIN;
305 #endif
306   else
307     return errno;
308
309   __set_errno (res);
310   return res;
311 }
312
313
314 #ifdef NO_COMPAT_NEEDED
315 strong_alias (INTERNAL (REENTRANT_NAME), REENTRANT_NAME);
316 #elif !defined FUNCTION2_NAME
317 # include <shlib-compat.h>
318 # if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1_2)
319 #  define OLD(name) OLD1 (name)
320 #  define OLD1(name) __old_##name
321
322 int
323 attribute_compat_text_section
324 OLD (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
325                       size_t buflen, LOOKUP_TYPE **result H_ERRNO_PARM)
326 {
327   int ret = INTERNAL (REENTRANT_NAME) (ADD_VARIABLES, resbuf, buffer,
328                                        buflen, result H_ERRNO_VAR);
329
330   if (ret != 0 || result == NULL)
331     ret = -1;
332
333   return ret;
334 }
335
336 #  define do_symbol_version(real, name, version) \
337   compat_symbol (libc, real, name, version)
338 do_symbol_version (OLD (REENTRANT_NAME), REENTRANT_NAME, GLIBC_2_0);
339 # endif
340
341 /* As INTERNAL (REENTRANT_NAME) may be hidden, we need an alias
342    in between so that the REENTRANT_NAME@@GLIBC_2.1.2 is not
343    hidden too.  */
344 strong_alias (INTERNAL (REENTRANT_NAME), NEW (REENTRANT_NAME));
345
346 # define do_default_symbol_version(real, name, version) \
347   versioned_symbol (libc, real, name, version)
348 do_default_symbol_version (NEW (REENTRANT_NAME),
349                            REENTRANT_NAME, GLIBC_2_1_2);
350 #endif
351
352 static_link_warning (REENTRANT_NAME)