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