]>
Commit | Line | Data |
---|---|---|
0ecb606c | 1 | /* Copyright (C) 1998-2005, 2006, 2007 Free Software Foundation, Inc. |
67479a70 UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
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. | |
67479a70 UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
67479a70 | 14 | |
41bdb6e2 AJ |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, write to the Free | |
17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
18 | 02111-1307 USA. */ | |
67479a70 | 19 | |
c207f23b | 20 | #include <assert.h> |
67479a70 UD |
21 | #include <errno.h> |
22 | #include <netdb.h> | |
23 | #include <resolv.h> | |
390955cb | 24 | #include <stdint.h> |
67479a70 UD |
25 | #include <stdio.h> |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
28 | #include <unistd.h> | |
29 | #include <arpa/nameser.h> | |
40c38b6c | 30 | #include <not-cancel.h> |
67479a70 | 31 | |
3f804c95 | 32 | #include "nscd-client.h" |
67479a70 UD |
33 | #include "nscd_proto.h" |
34 | ||
35 | int __nss_not_use_nscd_hosts; | |
36 | ||
37 | static int nscd_gethst_r (const char *key, size_t keylen, request_type type, | |
38 | struct hostent *resultbuf, char *buffer, | |
261eada2 UD |
39 | size_t buflen, struct hostent **result, |
40 | int *h_errnop) internal_function; | |
67479a70 UD |
41 | |
42 | ||
43 | int | |
44 | __nscd_gethostbyname_r (const char *name, struct hostent *resultbuf, | |
261eada2 UD |
45 | char *buffer, size_t buflen, struct hostent **result, |
46 | int *h_errnop) | |
67479a70 UD |
47 | { |
48 | request_type reqtype; | |
49 | ||
50 | reqtype = (_res.options & RES_USE_INET6) ? GETHOSTBYNAMEv6 : GETHOSTBYNAME; | |
51 | ||
52 | return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf, | |
261eada2 | 53 | buffer, buflen, result, h_errnop); |
67479a70 UD |
54 | } |
55 | ||
56 | ||
57 | int | |
58 | __nscd_gethostbyname2_r (const char *name, int af, struct hostent *resultbuf, | |
261eada2 UD |
59 | char *buffer, size_t buflen, struct hostent **result, |
60 | int *h_errnop) | |
67479a70 UD |
61 | { |
62 | request_type reqtype; | |
63 | ||
64 | reqtype = af == AF_INET6 ? GETHOSTBYNAMEv6 : GETHOSTBYNAME; | |
65 | ||
66 | return nscd_gethst_r (name, strlen (name) + 1, reqtype, resultbuf, | |
261eada2 | 67 | buffer, buflen, result, h_errnop); |
67479a70 UD |
68 | } |
69 | ||
70 | ||
71 | int | |
9d4d69b8 | 72 | __nscd_gethostbyaddr_r (const void *addr, socklen_t len, int type, |
67479a70 | 73 | struct hostent *resultbuf, char *buffer, size_t buflen, |
261eada2 | 74 | struct hostent **result, int *h_errnop) |
67479a70 UD |
75 | { |
76 | request_type reqtype; | |
77 | ||
78 | if (!((len == INADDRSZ && type == AF_INET) | |
79 | || (len == IN6ADDRSZ && type == AF_INET6))) | |
80 | /* LEN and TYPE do not match. */ | |
1670698f | 81 | return -1; |
67479a70 UD |
82 | |
83 | reqtype = type == AF_INET6 ? GETHOSTBYADDRv6 : GETHOSTBYADDR; | |
84 | ||
261eada2 | 85 | return nscd_gethst_r (addr, len, reqtype, resultbuf, buffer, buflen, result, |
67479a70 UD |
86 | h_errnop); |
87 | } | |
88 | ||
89 | ||
0ecb606c | 90 | libc_locked_map_ptr (, __hst_map_handle) attribute_hidden; |
c207f23b UD |
91 | /* Note that we only free the structure if necessary. The memory |
92 | mapping is not removed since it is not visible to the malloc | |
93 | handling. */ | |
ed2ced8a | 94 | libc_freeres_fn (hst_map_free) |
67479a70 | 95 | { |
ed2ced8a UD |
96 | if (__hst_map_handle.mapped != NO_MAPPING) |
97 | { | |
98 | void *p = __hst_map_handle.mapped; | |
99 | __hst_map_handle.mapped = NO_MAPPING; | |
100 | free (p); | |
101 | } | |
67479a70 UD |
102 | } |
103 | ||
104 | ||
105 | static int | |
813f4f4d | 106 | internal_function |
67479a70 UD |
107 | nscd_gethst_r (const char *key, size_t keylen, request_type type, |
108 | struct hostent *resultbuf, char *buffer, size_t buflen, | |
261eada2 | 109 | struct hostent **result, int *h_errnop) |
67479a70 | 110 | { |
0891f970 UD |
111 | int gc_cycle; |
112 | int nretries = 0; | |
113 | ||
114 | /* If the mapping is available, try to search there instead of | |
115 | communicating with the nscd. */ | |
116 | struct mapped_database *mapped; | |
ed2ced8a UD |
117 | mapped = __nscd_get_map_ref (GETFDHST, "hosts", &__hst_map_handle, |
118 | &gc_cycle); | |
0891f970 UD |
119 | |
120 | retry:; | |
c207f23b UD |
121 | const char *h_name = NULL; |
122 | const uint32_t *aliases_len = NULL; | |
123 | const char *addr_list = NULL; | |
124 | size_t addr_list_len = 0; | |
125 | int retval = -1; | |
c207f23b UD |
126 | const char *recend = (const char *) ~UINTMAX_C (0); |
127 | int sock = -1; | |
0ecb606c | 128 | hst_response_header hst_resp; |
af38d7ce | 129 | if (mapped != NO_MAPPING) |
67479a70 | 130 | { |
0ecb606c JJ |
131 | /* No const qualifier, as it can change during garbage collection. */ |
132 | struct datahead *found = __nscd_cache_search (type, key, keylen, mapped); | |
c207f23b UD |
133 | if (found != NULL) |
134 | { | |
0ecb606c JJ |
135 | h_name = (char *) (&found->data[0].hstdata + 1); |
136 | hst_resp = found->data[0].hstdata; | |
137 | aliases_len = (uint32_t *) (h_name + hst_resp.h_name_len); | |
c207f23b | 138 | addr_list = ((char *) aliases_len |
0ecb606c JJ |
139 | + hst_resp.h_aliases_cnt * sizeof (uint32_t)); |
140 | addr_list_len = hst_resp.h_addr_list_cnt * INADDRSZ; | |
141 | recend = (const char *) found->data + found->recsize; | |
142 | /* Now check if we can trust hst_resp fields. If GC is | |
143 | in progress, it can contain anything. */ | |
144 | if (mapped->head->gc_cycle != gc_cycle) | |
145 | { | |
146 | retval = -2; | |
147 | goto out; | |
148 | } | |
c207f23b UD |
149 | |
150 | #ifndef _STRING_ARCH_unaligned | |
151 | /* The aliases_len array in the mapped database might very | |
152 | well be unaligned. We will access it word-wise so on | |
153 | platforms which do not tolerate unaligned accesses we | |
154 | need to make an aligned copy. */ | |
155 | if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1)) | |
156 | != 0) | |
157 | { | |
0ecb606c | 158 | uint32_t *tmp = alloca (hst_resp.h_aliases_cnt |
c207f23b UD |
159 | * sizeof (uint32_t)); |
160 | aliases_len = memcpy (tmp, aliases_len, | |
0ecb606c | 161 | hst_resp.h_aliases_cnt |
c207f23b UD |
162 | * sizeof (uint32_t)); |
163 | } | |
164 | #endif | |
165 | if (type != GETHOSTBYADDR && type != GETHOSTBYNAME) | |
166 | { | |
0ecb606c | 167 | if (hst_resp.h_length == INADDRSZ) |
c207f23b | 168 | addr_list += addr_list_len; |
0ecb606c | 169 | addr_list_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ; |
c207f23b | 170 | } |
c207f23b UD |
171 | if (__builtin_expect ((const char *) addr_list + addr_list_len |
172 | > recend, 0)) | |
0ecb606c | 173 | goto out; |
c207f23b UD |
174 | } |
175 | } | |
176 | ||
0ecb606c | 177 | if (h_name == NULL) |
c207f23b | 178 | { |
0ecb606c JJ |
179 | sock = __nscd_open_socket (key, keylen, type, &hst_resp, |
180 | sizeof (hst_resp)); | |
c207f23b UD |
181 | if (sock == -1) |
182 | { | |
183 | __nss_not_use_nscd_hosts = 1; | |
0ecb606c | 184 | goto out; |
c207f23b | 185 | } |
67479a70 UD |
186 | } |
187 | ||
16aac663 UD |
188 | /* No value found so far. */ |
189 | *result = NULL; | |
190 | ||
0ecb606c | 191 | if (__builtin_expect (hst_resp.found == -1, 0)) |
67479a70 UD |
192 | { |
193 | /* The daemon does not cache this database. */ | |
67479a70 | 194 | __nss_not_use_nscd_hosts = 1; |
c207f23b | 195 | goto out_close; |
67479a70 UD |
196 | } |
197 | ||
0ecb606c | 198 | if (hst_resp.found == 1) |
67479a70 | 199 | { |
40c38b6c | 200 | struct iovec vec[4]; |
67479a70 | 201 | char *cp = buffer; |
3810076f UD |
202 | uintptr_t align1; |
203 | uintptr_t align2; | |
67479a70 UD |
204 | size_t total_len; |
205 | ssize_t cnt; | |
206 | char *ignore; | |
207 | int n; | |
208 | ||
49c091e5 | 209 | /* A first check whether the buffer is sufficiently large is possible. */ |
67479a70 | 210 | /* Now allocate the buffer the array for the group members. We must |
3810076f UD |
211 | align the pointer and the base of the h_addr_list pointers. */ |
212 | align1 = ((__alignof__ (char *) - (cp - ((char *) 0))) | |
213 | & (__alignof__ (char *) - 1)); | |
0ecb606c | 214 | align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp.h_name_len) |
3810076f UD |
215 | - ((char *) 0))) |
216 | & (__alignof__ (char *) - 1)); | |
0ecb606c JJ |
217 | if (buflen < (align1 + hst_resp.h_name_len + align2 |
218 | + ((hst_resp.h_aliases_cnt + hst_resp.h_addr_list_cnt | |
c207f23b | 219 | + 2) |
67479a70 | 220 | * sizeof (char *)) |
0ecb606c JJ |
221 | + hst_resp.h_addr_list_cnt * (type == AF_INET |
222 | ? INADDRSZ : IN6ADDRSZ))) | |
67479a70 UD |
223 | { |
224 | no_room: | |
0ecb606c | 225 | *h_errnop = NETDB_INTERNAL; |
67479a70 | 226 | __set_errno (ERANGE); |
261eada2 | 227 | retval = ERANGE; |
c207f23b | 228 | goto out_close; |
67479a70 | 229 | } |
3810076f | 230 | cp += align1; |
67479a70 UD |
231 | |
232 | /* Prepare the result as far as we can. */ | |
233 | resultbuf->h_aliases = (char **) cp; | |
0ecb606c | 234 | cp += (hst_resp.h_aliases_cnt + 1) * sizeof (char *); |
67479a70 | 235 | resultbuf->h_addr_list = (char **) cp; |
0ecb606c | 236 | cp += (hst_resp.h_addr_list_cnt + 1) * sizeof (char *); |
67479a70 UD |
237 | |
238 | resultbuf->h_name = cp; | |
0ecb606c | 239 | cp += hst_resp.h_name_len + align2; |
67479a70 | 240 | |
67479a70 UD |
241 | if (type == GETHOSTBYADDR || type == GETHOSTBYNAME) |
242 | { | |
67479a70 UD |
243 | resultbuf->h_addrtype = AF_INET; |
244 | resultbuf->h_length = INADDRSZ; | |
67479a70 UD |
245 | } |
246 | else | |
247 | { | |
c207f23b UD |
248 | resultbuf->h_addrtype = AF_INET6; |
249 | resultbuf->h_length = IN6ADDRSZ; | |
250 | } | |
0ecb606c | 251 | for (cnt = 0; cnt < hst_resp.h_addr_list_cnt; ++cnt) |
c207f23b UD |
252 | { |
253 | resultbuf->h_addr_list[cnt] = cp; | |
254 | cp += resultbuf->h_length; | |
255 | } | |
256 | resultbuf->h_addr_list[cnt] = NULL; | |
67479a70 | 257 | |
c207f23b UD |
258 | if (h_name == NULL) |
259 | { | |
260 | vec[0].iov_base = resultbuf->h_name; | |
0ecb606c JJ |
261 | vec[0].iov_len = hst_resp.h_name_len; |
262 | total_len = hst_resp.h_name_len; | |
c207f23b | 263 | n = 1; |
67479a70 | 264 | |
0ecb606c | 265 | if (hst_resp.h_aliases_cnt > 0) |
c207f23b | 266 | { |
0ecb606c | 267 | aliases_len = alloca (hst_resp.h_aliases_cnt |
c207f23b UD |
268 | * sizeof (uint32_t)); |
269 | vec[n].iov_base = (void *) aliases_len; | |
0ecb606c | 270 | vec[n].iov_len = hst_resp.h_aliases_cnt * sizeof (uint32_t); |
67479a70 | 271 | |
0ecb606c | 272 | total_len += hst_resp.h_aliases_cnt * sizeof (uint32_t); |
c207f23b UD |
273 | ++n; |
274 | } | |
67479a70 | 275 | |
c207f23b | 276 | if (type == GETHOSTBYADDR || type == GETHOSTBYNAME) |
67479a70 | 277 | { |
c207f23b | 278 | vec[n].iov_base = resultbuf->h_addr_list[0]; |
0ecb606c | 279 | vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ; |
c207f23b | 280 | |
0ecb606c | 281 | total_len += hst_resp.h_addr_list_cnt * INADDRSZ; |
c207f23b UD |
282 | |
283 | ++n; | |
67479a70 | 284 | } |
c207f23b UD |
285 | else |
286 | { | |
0ecb606c | 287 | if (hst_resp.h_length == INADDRSZ) |
c207f23b | 288 | { |
0ecb606c | 289 | ignore = alloca (hst_resp.h_addr_list_cnt * INADDRSZ); |
c207f23b | 290 | vec[n].iov_base = ignore; |
0ecb606c | 291 | vec[n].iov_len = hst_resp.h_addr_list_cnt * INADDRSZ; |
67479a70 | 292 | |
0ecb606c | 293 | total_len += hst_resp.h_addr_list_cnt * INADDRSZ; |
67479a70 | 294 | |
c207f23b UD |
295 | ++n; |
296 | } | |
67479a70 | 297 | |
c207f23b | 298 | vec[n].iov_base = resultbuf->h_addr_list[0]; |
0ecb606c | 299 | vec[n].iov_len = hst_resp.h_addr_list_cnt * IN6ADDRSZ; |
67479a70 | 300 | |
0ecb606c | 301 | total_len += hst_resp.h_addr_list_cnt * IN6ADDRSZ; |
c207f23b UD |
302 | |
303 | ++n; | |
304 | } | |
305 | ||
0ecb606c | 306 | if ((size_t) __readvall (sock, vec, n) != total_len) |
c207f23b UD |
307 | goto out_close; |
308 | } | |
309 | else | |
310 | { | |
0ecb606c | 311 | memcpy (resultbuf->h_name, h_name, hst_resp.h_name_len); |
c207f23b UD |
312 | memcpy (resultbuf->h_addr_list[0], addr_list, addr_list_len); |
313 | } | |
67479a70 UD |
314 | |
315 | /* Now we also can read the aliases. */ | |
316 | total_len = 0; | |
0ecb606c | 317 | for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt) |
67479a70 UD |
318 | { |
319 | resultbuf->h_aliases[cnt] = cp; | |
320 | cp += aliases_len[cnt]; | |
321 | total_len += aliases_len[cnt]; | |
322 | } | |
323 | resultbuf->h_aliases[cnt] = NULL; | |
324 | ||
c207f23b UD |
325 | if (__builtin_expect ((const char *) addr_list + addr_list_len |
326 | + total_len > recend, 0)) | |
0ecb606c JJ |
327 | { |
328 | /* aliases_len array might contain garbage during nscd GC cycle, | |
329 | retry rather than fail in that case. */ | |
330 | if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle) | |
331 | retval = -2; | |
332 | goto out_close; | |
333 | } | |
67479a70 | 334 | /* See whether this would exceed the buffer capacity. */ |
c207f23b | 335 | if (__builtin_expect (cp > buffer + buflen, 0)) |
0ecb606c JJ |
336 | { |
337 | /* aliases_len array might contain garbage during nscd GC cycle, | |
338 | retry rather than fail in that case. */ | |
339 | if (addr_list != NULL && mapped->head->gc_cycle != gc_cycle) | |
340 | { | |
341 | retval = -2; | |
342 | goto out_close; | |
343 | } | |
344 | goto no_room; | |
345 | } | |
67479a70 UD |
346 | |
347 | /* And finally read the aliases. */ | |
c207f23b UD |
348 | if (addr_list == NULL) |
349 | { | |
0ecb606c JJ |
350 | if (total_len == 0 |
351 | || ((size_t) __readall (sock, resultbuf->h_aliases[0], total_len) | |
352 | == total_len)) | |
c207f23b UD |
353 | { |
354 | retval = 0; | |
355 | *result = resultbuf; | |
356 | } | |
357 | } | |
358 | else | |
261eada2 | 359 | { |
c207f23b UD |
360 | memcpy (resultbuf->h_aliases[0], |
361 | (const char *) addr_list + addr_list_len, total_len); | |
362 | ||
5429ff76 | 363 | /* Try to detect corrupt databases. */ |
0ecb606c JJ |
364 | if (resultbuf->h_name[hst_resp.h_name_len - 1] != '\0' |
365 | || ({for (cnt = 0; cnt < hst_resp.h_aliases_cnt; ++cnt) | |
5429ff76 UD |
366 | if (resultbuf->h_aliases[cnt][aliases_len[cnt] - 1] |
367 | != '\0') | |
368 | break; | |
0ecb606c JJ |
369 | cnt < hst_resp.h_aliases_cnt; })) |
370 | { | |
371 | /* We cannot use the database. */ | |
372 | if (mapped->head->gc_cycle != gc_cycle) | |
373 | retval = -2; | |
374 | goto out_close; | |
375 | } | |
5429ff76 | 376 | |
261eada2 UD |
377 | retval = 0; |
378 | *result = resultbuf; | |
379 | } | |
67479a70 UD |
380 | } |
381 | else | |
382 | { | |
383 | /* Store the error number. */ | |
0ecb606c | 384 | *h_errnop = hst_resp.error; |
67479a70 | 385 | |
336dfb2d UD |
386 | /* The `errno' to some value != ERANGE. */ |
387 | __set_errno (ENOENT); | |
261eada2 UD |
388 | /* Even though we have not found anything, the result is zero. */ |
389 | retval = 0; | |
67479a70 | 390 | } |
12c80513 | 391 | |
c207f23b UD |
392 | out_close: |
393 | if (sock != -1) | |
394 | close_not_cancel_no_status (sock); | |
12c80513 | 395 | out: |
0ecb606c | 396 | if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0) |
0891f970 UD |
397 | { |
398 | /* When we come here this means there has been a GC cycle while we | |
399 | were looking for the data. This means the data might have been | |
400 | inconsistent. Retry if possible. */ | |
0ecb606c | 401 | if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1) |
0891f970 UD |
402 | { |
403 | /* nscd is just running gc now. Disable using the mapping. */ | |
0ecb606c JJ |
404 | if (atomic_decrement_val (&mapped->counter) == 0) |
405 | __nscd_unmap (mapped); | |
0891f970 UD |
406 | mapped = NO_MAPPING; |
407 | } | |
408 | ||
0ecb606c JJ |
409 | if (retval != -1) |
410 | goto retry; | |
0891f970 | 411 | } |
12c80513 | 412 | |
261eada2 | 413 | return retval; |
67479a70 | 414 | } |