tst-nss-files-hosts-getent.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /* Enumerate /etc/hosts with a long line (bug 18991).
  2. Copyright (C) 2018-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <http://www.gnu.org/licenses/>. */
  15. #include <dlfcn.h>
  16. #include <errno.h>
  17. #include <gnu/lib-names.h>
  18. #include <netdb.h>
  19. #include <nss.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <support/check.h>
  23. #include <support/check_nss.h>
  24. #include <support/namespace.h>
  25. #include <support/support.h>
  26. #include <support/test-driver.h>
  27. #include <support/xmemstream.h>
  28. #include <support/xstdio.h>
  29. #include <support/xunistd.h>
  30. struct support_chroot *chroot_env;
  31. /* Number of alias names in the long line. This is varied to catch
  32. different cases where the ERANGE handling can go wrong (line buffer
  33. length, alias buffer). */
  34. static int name_count;
  35. /* Write /etc/hosts, from outside of the chroot. */
  36. static void
  37. write_hosts (void)
  38. {
  39. FILE *fp = xfopen (chroot_env->path_hosts, "w");
  40. fputs ("127.0.0.1 localhost localhost.localdomain\n", fp);
  41. fputs ("192.0.2.2 host2.example.com\n", fp);
  42. fputs ("192.0.2.1", fp);
  43. for (int i = 0; i < name_count; ++i)
  44. fprintf (fp, " host%d.example.com", i);
  45. fputs ("\n192.0.2.80 www.example.com\n"
  46. "192.0.2.5 host5.example.com\n"
  47. "192.0.2.81 www1.example.com\n", fp);
  48. xfclose (fp);
  49. }
  50. const char *host1_expected =
  51. "name: localhost\n"
  52. "alias: localhost.localdomain\n"
  53. "address: 127.0.0.1\n";
  54. const char *host2_expected =
  55. "name: host2.example.com\n"
  56. "address: 192.0.2.2\n";
  57. const char *host4_expected =
  58. "name: www.example.com\n"
  59. "address: 192.0.2.80\n";
  60. const char *host5_expected =
  61. "name: host5.example.com\n"
  62. "address: 192.0.2.5\n";
  63. const char *host6_expected =
  64. "name: www1.example.com\n"
  65. "address: 192.0.2.81\n";
  66. static void
  67. prepare (int argc, char **argv)
  68. {
  69. chroot_env = support_chroot_create
  70. ((struct support_chroot_configuration)
  71. {
  72. .resolv_conf = "",
  73. .hosts = "", /* Filled in by write_hosts. */
  74. .host_conf = "multi on\n",
  75. });
  76. }
  77. /* If -1, no sethostent call. Otherwise, pass do_stayopen as the
  78. sethostent argument. */
  79. static int do_stayopen;
  80. /* If non-zero, perform an endostent call. */
  81. static int do_endent;
  82. static void
  83. subprocess_getent (void *closure)
  84. {
  85. xchroot (chroot_env->path_chroot);
  86. errno = 0;
  87. if (do_stayopen >= 0)
  88. sethostent (do_stayopen);
  89. TEST_VERIFY (errno == 0);
  90. int i = 0;
  91. while (true)
  92. {
  93. struct xmemstream expected;
  94. xopen_memstream (&expected);
  95. switch (++i)
  96. {
  97. case 1:
  98. fputs (host1_expected, expected.out);
  99. break;
  100. case 2:
  101. fputs (host2_expected, expected.out);
  102. break;
  103. case 3:
  104. fputs ("name: host0.example.com\n", expected.out);
  105. for (int j = 1; j < name_count; ++j)
  106. fprintf (expected.out, "alias: host%d.example.com\n", j);
  107. fputs ("address: 192.0.2.1\n", expected.out);
  108. break;
  109. case 4:
  110. fputs (host4_expected, expected.out);
  111. break;
  112. case 5:
  113. fputs (host5_expected, expected.out);
  114. break;
  115. case 6:
  116. fputs (host6_expected, expected.out);
  117. break;
  118. default:
  119. fprintf (expected.out, "*** unexpected host %d ***\n", i);
  120. break;
  121. }
  122. xfclose_memstream (&expected);
  123. char *context = xasprintf ("do_stayopen=%d host=%d", do_stayopen, i);
  124. errno = 0;
  125. struct hostent *e = gethostent ();
  126. if (e == NULL)
  127. {
  128. TEST_VERIFY (errno == 0);
  129. break;
  130. }
  131. check_hostent (context, e, expected.buffer);
  132. free (context);
  133. free (expected.buffer);
  134. }
  135. errno = 0;
  136. if (do_endent)
  137. endhostent ();
  138. TEST_VERIFY (errno == 0);
  139. /* Exercise process termination. */
  140. exit (0);
  141. }
  142. /* getaddrinfo test. To be run from a subprocess. */
  143. static void
  144. test_gai (int family)
  145. {
  146. struct addrinfo hints =
  147. {
  148. .ai_family = family,
  149. .ai_protocol = IPPROTO_TCP,
  150. .ai_socktype = SOCK_STREAM,
  151. };
  152. struct addrinfo *ai;
  153. int ret = getaddrinfo ("host2.example.com", "80", &hints, &ai);
  154. check_addrinfo ("host2.example.com", ai, ret,
  155. "address: STREAM/TCP 192.0.2.2 80\n"
  156. "address: STREAM/TCP 192.0.2.1 80\n");
  157. ret = getaddrinfo ("host5.example.com", "80", &hints, &ai);
  158. check_addrinfo ("host5.example.com", ai, ret,
  159. "address: STREAM/TCP 192.0.2.1 80\n"
  160. "address: STREAM/TCP 192.0.2.5 80\n");
  161. ret = getaddrinfo ("www.example.com", "80", &hints, &ai);
  162. check_addrinfo ("www.example.com", ai, ret,
  163. "address: STREAM/TCP 192.0.2.80 80\n");
  164. ret = getaddrinfo ("www1.example.com", "80", &hints, &ai);
  165. check_addrinfo ("www1.example.com", ai, ret,
  166. "address: STREAM/TCP 192.0.2.81 80\n");
  167. }
  168. /* Subprocess routine for gethostbyname/getaddrinfo testing. */
  169. static void
  170. subprocess_gethost (void *closure)
  171. {
  172. xchroot (chroot_env->path_chroot);
  173. /* This tests enlarging the read buffer in the multi case. */
  174. struct xmemstream expected;
  175. xopen_memstream (&expected);
  176. fputs ("name: host2.example.com\n", expected.out);
  177. for (int j = 1; j < name_count; ++j)
  178. /* NB: host2 is duplicated in the alias list. */
  179. fprintf (expected.out, "alias: host%d.example.com\n", j);
  180. fputs ("alias: host0.example.com\n"
  181. "address: 192.0.2.2\n"
  182. "address: 192.0.2.1\n",
  183. expected.out);
  184. xfclose_memstream (&expected);
  185. check_hostent ("host2.example.com",
  186. gethostbyname ("host2.example.com"),
  187. expected.buffer);
  188. free (expected.buffer);
  189. /* Similarly, but with a different order in the /etc/hosts file. */
  190. xopen_memstream (&expected);
  191. fputs ("name: host0.example.com\n", expected.out);
  192. for (int j = 1; j < name_count; ++j)
  193. fprintf (expected.out, "alias: host%d.example.com\n", j);
  194. /* NB: host5 is duplicated in the alias list. */
  195. fputs ("alias: host5.example.com\n"
  196. "address: 192.0.2.1\n"
  197. "address: 192.0.2.5\n",
  198. expected.out);
  199. xfclose_memstream (&expected);
  200. check_hostent ("host5.example.com",
  201. gethostbyname ("host5.example.com"),
  202. expected.buffer);
  203. free (expected.buffer);
  204. check_hostent ("www.example.com",
  205. gethostbyname ("www.example.com"),
  206. host4_expected);
  207. check_hostent ("www1.example.com",
  208. gethostbyname ("www1.example.com"),
  209. host6_expected);
  210. test_gai (AF_INET);
  211. test_gai (AF_UNSPEC);
  212. }
  213. static int
  214. do_test (void)
  215. {
  216. support_become_root ();
  217. if (!support_can_chroot ())
  218. return EXIT_UNSUPPORTED;
  219. __nss_configure_lookup ("hosts", "files");
  220. if (dlopen (LIBNSS_FILES_SO, RTLD_LAZY) == NULL)
  221. FAIL_EXIT1 ("could not load " LIBNSS_DNS_SO ": %s", dlerror ());
  222. /* Each name takes about 20 bytes, so this covers a wide range of
  223. buffer sizes, from less than 1000 bytes to about 18000 bytes. */
  224. for (name_count = 40; name_count <= 850; ++name_count)
  225. {
  226. write_hosts ();
  227. for (do_stayopen = -1; do_stayopen < 2; ++do_stayopen)
  228. for (do_endent = 0; do_endent < 2; ++do_endent)
  229. {
  230. if (test_verbose > 0)
  231. printf ("info: name_count=%d do_stayopen=%d do_endent=%d\n",
  232. name_count, do_stayopen, do_endent);
  233. support_isolate_in_subprocess (subprocess_getent, NULL);
  234. }
  235. support_isolate_in_subprocess (subprocess_gethost, NULL);
  236. }
  237. support_chroot_free (chroot_env);
  238. return 0;
  239. }
  240. #define PREPARE prepare
  241. #include <support/test-driver.c>