]>
Commit | Line | Data |
---|---|---|
11bf311e | 1 | /* Copyright (C) 1998-2005, 2006 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 | ||
6f8a7dff | 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:; | |
11bf311e | 121 | const hst_response_header *hst_resp = NULL; |
c207f23b UD |
122 | const char *h_name = NULL; |
123 | const uint32_t *aliases_len = NULL; | |
124 | const char *addr_list = NULL; | |
125 | size_t addr_list_len = 0; | |
126 | int retval = -1; | |
c207f23b UD |
127 | const char *recend = (const char *) ~UINTMAX_C (0); |
128 | int sock = -1; | |
af38d7ce | 129 | if (mapped != NO_MAPPING) |
67479a70 | 130 | { |
11bf311e UD |
131 | const struct datahead *found = __nscd_cache_search (type, key, keylen, |
132 | mapped); | |
c207f23b UD |
133 | if (found != NULL) |
134 | { | |
11bf311e UD |
135 | hst_resp = &found->data[0].hstdata; |
136 | h_name = (char *) (hst_resp + 1); | |
137 | aliases_len = (uint32_t *) (h_name + hst_resp->h_name_len); | |
c207f23b | 138 | addr_list = ((char *) aliases_len |
11bf311e UD |
139 | + hst_resp->h_aliases_cnt * sizeof (uint32_t)); |
140 | addr_list_len = hst_resp->h_addr_list_cnt * INADDRSZ; | |
c207f23b UD |
141 | |
142 | #ifndef _STRING_ARCH_unaligned | |
143 | /* The aliases_len array in the mapped database might very | |
144 | well be unaligned. We will access it word-wise so on | |
145 | platforms which do not tolerate unaligned accesses we | |
146 | need to make an aligned copy. */ | |
147 | if (((uintptr_t) aliases_len & (__alignof__ (*aliases_len) - 1)) | |
148 | != 0) | |
149 | { | |
11bf311e | 150 | uint32_t *tmp = alloca (hst_resp->h_aliases_cnt |
c207f23b UD |
151 | * sizeof (uint32_t)); |
152 | aliases_len = memcpy (tmp, aliases_len, | |
11bf311e | 153 | hst_resp->h_aliases_cnt |
c207f23b UD |
154 | * sizeof (uint32_t)); |
155 | } | |
156 | #endif | |
157 | if (type != GETHOSTBYADDR && type != GETHOSTBYNAME) | |
158 | { | |
11bf311e | 159 | if (hst_resp->h_length == INADDRSZ) |
c207f23b | 160 | addr_list += addr_list_len; |
11bf311e | 161 | addr_list_len = hst_resp->h_addr_list_cnt * IN6ADDRSZ; |
c207f23b | 162 | } |
11bf311e | 163 | recend = (const char *) found->data + found->recsize; |
c207f23b UD |
164 | if (__builtin_expect ((const char *) addr_list + addr_list_len |
165 | > recend, 0)) | |
11bf311e | 166 | goto out_close; |
c207f23b UD |
167 | } |
168 | } | |
169 | ||
11bf311e UD |
170 | hst_response_header hst_resp_mem; |
171 | if (hst_resp == NULL) | |
c207f23b | 172 | { |
11bf311e UD |
173 | sock = __nscd_open_socket (key, keylen, type, &hst_resp_mem, |
174 | sizeof (hst_resp_mem)); | |
c207f23b UD |
175 | if (sock == -1) |
176 | { | |
177 | __nss_not_use_nscd_hosts = 1; | |
11bf311e | 178 | goto out;; |
c207f23b | 179 | } |
11bf311e UD |
180 | |
181 | hst_resp = &hst_resp_mem; | |
67479a70 UD |
182 | } |
183 | ||
16aac663 UD |
184 | /* No value found so far. */ |
185 | *result = NULL; | |
186 | ||
11bf311e | 187 | if (__builtin_expect (hst_resp->found == -1, 0)) |
67479a70 UD |
188 | { |
189 | /* The daemon does not cache this database. */ | |
67479a70 | 190 | __nss_not_use_nscd_hosts = 1; |
c207f23b | 191 | goto out_close; |
67479a70 UD |
192 | } |
193 | ||
11bf311e | 194 | if (hst_resp->found == 1) |
67479a70 | 195 | { |
40c38b6c | 196 | struct iovec vec[4]; |
67479a70 | 197 | char *cp = buffer; |
3810076f UD |
198 | uintptr_t align1; |
199 | uintptr_t align2; | |
67479a70 UD |
200 | size_t total_len; |
201 | ssize_t cnt; | |
202 | char *ignore; | |
203 | int n; | |
204 | ||
49c091e5 | 205 | /* A first check whether the buffer is sufficiently large is possible. */ |
67479a70 | 206 | /* Now allocate the buffer the array for the group members. We must |
3810076f UD |
207 | align the pointer and the base of the h_addr_list pointers. */ |
208 | align1 = ((__alignof__ (char *) - (cp - ((char *) 0))) | |
209 | & (__alignof__ (char *) - 1)); | |
11bf311e | 210 | align2 = ((__alignof__ (char *) - ((cp + align1 + hst_resp->h_name_len) |
3810076f UD |
211 | - ((char *) 0))) |
212 | & (__alignof__ (char *) - 1)); | |
11bf311e UD |
213 | if (buflen < (align1 + hst_resp->h_name_len + align2 |
214 | + ((hst_resp->h_aliases_cnt + hst_resp->h_addr_list_cnt | |
c207f23b | 215 | + 2) |
67479a70 | 216 | * sizeof (char *)) |
11bf311e UD |
217 | + hst_resp->h_addr_list_cnt * (type == AF_INET |
218 | ? INADDRSZ : IN6ADDRSZ))) | |
67479a70 UD |
219 | { |
220 | no_room: | |
4379b403 | 221 | *h_errnop = NETDB_INTERNAL; |
67479a70 | 222 | __set_errno (ERANGE); |
261eada2 | 223 | retval = ERANGE; |
c207f23b | 224 | goto out_close; |
67479a70 | 225 | } |
3810076f | 226 | cp += align1; |
67479a70 UD |
227 | |
228 | /* Prepare the result as far as we can. */ | |
229 | resultbuf->h_aliases = (char **) cp; | |
11bf311e | 230 | cp += (hst_resp->h_aliases_cnt + 1) * sizeof (char *); |
67479a70 | 231 | resultbuf->h_addr_list = (char **) cp; |
11bf311e | 232 | cp += (hst_resp->h_addr_list_cnt + 1) * sizeof (char *); |
67479a70 UD |
233 | |
234 | resultbuf->h_name = cp; | |
11bf311e | 235 | cp += hst_resp->h_name_len + align2; |
67479a70 | 236 | |
67479a70 UD |
237 | if (type == GETHOSTBYADDR || type == GETHOSTBYNAME) |
238 | { | |
67479a70 UD |
239 | resultbuf->h_addrtype = AF_INET; |
240 | resultbuf->h_length = INADDRSZ; | |
67479a70 UD |
241 | } |
242 | else | |
243 | { | |
c207f23b UD |
244 | resultbuf->h_addrtype = AF_INET6; |
245 | resultbuf->h_length = IN6ADDRSZ; | |
246 | } | |
11bf311e | 247 | for (cnt = 0; cnt < hst_resp->h_addr_list_cnt; ++cnt) |
c207f23b UD |
248 | { |
249 | resultbuf->h_addr_list[cnt] = cp; | |
250 | cp += resultbuf->h_length; | |
251 | } | |
252 | resultbuf->h_addr_list[cnt] = NULL; | |
67479a70 | 253 | |
c207f23b UD |
254 | if (h_name == NULL) |
255 | { | |
256 | vec[0].iov_base = resultbuf->h_name; | |
11bf311e UD |
257 | vec[0].iov_len = hst_resp->h_name_len; |
258 | total_len = hst_resp->h_name_len; | |
c207f23b | 259 | n = 1; |
67479a70 | 260 | |
11bf311e | 261 | if (hst_resp->h_aliases_cnt > 0) |
c207f23b | 262 | { |
11bf311e | 263 | aliases_len = alloca (hst_resp->h_aliases_cnt |
c207f23b UD |
264 | * sizeof (uint32_t)); |
265 | vec[n].iov_base = (void *) aliases_len; | |
11bf311e | 266 | vec[n].iov_len = hst_resp->h_aliases_cnt * sizeof (uint32_t); |
67479a70 | 267 | |
11bf311e | 268 | total_len += hst_resp->h_aliases_cnt * sizeof (uint32_t); |
c207f23b UD |
269 | ++n; |
270 | } | |
67479a70 | 271 | |
c207f23b | 272 | if (type == GETHOSTBYADDR || type == GETHOSTBYNAME) |
67479a70 | 273 | { |
c207f23b | 274 | vec[n].iov_base = resultbuf->h_addr_list[0]; |
11bf311e | 275 | vec[n].iov_len = hst_resp->h_addr_list_cnt * INADDRSZ; |
c207f23b | 276 | |
11bf311e | 277 | total_len += hst_resp->h_addr_list_cnt * INADDRSZ; |
c207f23b UD |
278 | |
279 | ++n; | |
67479a70 | 280 | } |
c207f23b UD |
281 | else |
282 | { | |
11bf311e | 283 | if (hst_resp->h_length == INADDRSZ) |
c207f23b | 284 | { |
11bf311e | 285 | ignore = alloca (hst_resp->h_addr_list_cnt * INADDRSZ); |
c207f23b | 286 | vec[n].iov_base = ignore; |
11bf311e | 287 | vec[n].iov_len = hst_resp->h_addr_list_cnt * INADDRSZ; |
67479a70 | 288 | |
11bf311e | 289 | total_len += hst_resp->h_addr_list_cnt * INADDRSZ; |
67479a70 | 290 | |
c207f23b UD |
291 | ++n; |
292 | } | |
67479a70 | 293 | |
c207f23b | 294 | vec[n].iov_base = resultbuf->h_addr_list[0]; |
11bf311e | 295 | vec[n].iov_len = hst_resp->h_addr_list_cnt * IN6ADDRSZ; |
67479a70 | 296 | |
11bf311e | 297 | total_len += hst_resp->h_addr_list_cnt * IN6ADDRSZ; |
c207f23b UD |
298 | |
299 | ++n; | |
300 | } | |
301 | ||
d2dc7d84 | 302 | if ((size_t) __readvall (sock, vec, n) != total_len) |
c207f23b UD |
303 | goto out_close; |
304 | } | |
305 | else | |
306 | { | |
11bf311e | 307 | memcpy (resultbuf->h_name, h_name, hst_resp->h_name_len); |
c207f23b UD |
308 | memcpy (resultbuf->h_addr_list[0], addr_list, addr_list_len); |
309 | } | |
67479a70 UD |
310 | |
311 | /* Now we also can read the aliases. */ | |
312 | total_len = 0; | |
11bf311e | 313 | for (cnt = 0; cnt < hst_resp->h_aliases_cnt; ++cnt) |
67479a70 UD |
314 | { |
315 | resultbuf->h_aliases[cnt] = cp; | |
316 | cp += aliases_len[cnt]; | |
317 | total_len += aliases_len[cnt]; | |
318 | } | |
319 | resultbuf->h_aliases[cnt] = NULL; | |
320 | ||
c207f23b UD |
321 | if (__builtin_expect ((const char *) addr_list + addr_list_len |
322 | + total_len > recend, 0)) | |
11bf311e | 323 | goto out_close; |
67479a70 | 324 | /* See whether this would exceed the buffer capacity. */ |
c207f23b | 325 | if (__builtin_expect (cp > buffer + buflen, 0)) |
11bf311e | 326 | goto no_room; |
67479a70 UD |
327 | |
328 | /* And finally read the aliases. */ | |
c207f23b UD |
329 | if (addr_list == NULL) |
330 | { | |
74ac0a89 UD |
331 | if (total_len == 0 |
332 | || ((size_t) __readall (sock, resultbuf->h_aliases[0], total_len) | |
333 | == total_len)) | |
c207f23b UD |
334 | { |
335 | retval = 0; | |
336 | *result = resultbuf; | |
337 | } | |
338 | } | |
339 | else | |
261eada2 | 340 | { |
c207f23b UD |
341 | memcpy (resultbuf->h_aliases[0], |
342 | (const char *) addr_list + addr_list_len, total_len); | |
343 | ||
5429ff76 | 344 | /* Try to detect corrupt databases. */ |
11bf311e UD |
345 | if (resultbuf->h_name[hst_resp->h_name_len - 1] != '\0' |
346 | || ({for (cnt = 0; cnt < hst_resp->h_aliases_cnt; ++cnt) | |
5429ff76 UD |
347 | if (resultbuf->h_aliases[cnt][aliases_len[cnt] - 1] |
348 | != '\0') | |
349 | break; | |
11bf311e UD |
350 | cnt < hst_resp->h_aliases_cnt; })) |
351 | /* We cannot use the database. */ | |
352 | goto out_close; | |
5429ff76 | 353 | |
261eada2 UD |
354 | retval = 0; |
355 | *result = resultbuf; | |
356 | } | |
67479a70 UD |
357 | } |
358 | else | |
359 | { | |
360 | /* Store the error number. */ | |
11bf311e | 361 | *h_errnop = hst_resp->error; |
67479a70 | 362 | |
336dfb2d UD |
363 | /* The `errno' to some value != ERANGE. */ |
364 | __set_errno (ENOENT); | |
261eada2 UD |
365 | /* Even though we have not found anything, the result is zero. */ |
366 | retval = 0; | |
67479a70 | 367 | } |
12c80513 | 368 | |
c207f23b UD |
369 | out_close: |
370 | if (sock != -1) | |
371 | close_not_cancel_no_status (sock); | |
12c80513 | 372 | out: |
11bf311e | 373 | if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0 && retval != -1) |
0891f970 UD |
374 | { |
375 | /* When we come here this means there has been a GC cycle while we | |
376 | were looking for the data. This means the data might have been | |
377 | inconsistent. Retry if possible. */ | |
11bf311e | 378 | if ((gc_cycle & 1) != 0 || ++nretries == 5) |
0891f970 UD |
379 | { |
380 | /* nscd is just running gc now. Disable using the mapping. */ | |
11bf311e | 381 | __nscd_unmap (mapped); |
0891f970 UD |
382 | mapped = NO_MAPPING; |
383 | } | |
384 | ||
11bf311e | 385 | goto retry; |
0891f970 | 386 | } |
12c80513 | 387 | |
261eada2 | 388 | return retval; |
67479a70 | 389 | } |