nscd_gethst_r.c 12 KB

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