1 /* Test that nsswitch.conf reloading actually works.
2 Copyright (C) 2020-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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 <nss.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <errno.h>
25 #include <pwd.h>
26
27 #include <support/support.h>
28 #include <support/check.h>
29
30 #include "nss_test.h"
31
32 /* Size of buffers used by *_r functions. */
33 #define TESTBUFLEN 4096
34
35 static struct passwd pwd_table_1[] = {
36 PWD (100),
37 PWD (30),
38 PWD (200),
39 PWD (60),
40 PWD (20000),
41 PWD_LAST ()
42 };
43
44 static const char *hostaddr_5[] =
45 {
46 "ABCD", "abcd", "1234", NULL
47 };
48
49 static const char *hostaddr_15[] =
50 {
51 "4321", "ghij", NULL
52 };
53
54 static const char *hostaddr_25[] =
55 {
56 "WXYZ", NULL
57 };
58
59
60 static struct hostent host_table_1[] = {
61 HOST (5),
62 HOST (15),
63 HOST (25),
64 HOST_LAST ()
65 };
66
67 void
_nss_test1_init_hook(test_tables * t)68 _nss_test1_init_hook(test_tables *t)
69 {
70 t->pwd_table = pwd_table_1;
71 t->host_table = host_table_1;
72 }
73
74 /* The first of these must not appear in pwd_table_1. */
75 static struct passwd pwd_table_2[] = {
76 PWD (5),
77 PWD_N(200, "name30"),
78 PWD (16),
79 PWD_LAST ()
80 };
81
82 static const char *hostaddr_6[] =
83 {
84 "mnop", NULL
85 };
86
87 static const char *hostaddr_16[] =
88 {
89 "7890", "a1b2", NULL
90 };
91
92 static const char *hostaddr_26[] =
93 {
94 "qwer", "tyui", NULL
95 };
96
97 static struct hostent host_table_2[] = {
98 HOST (6),
99 HOST (16),
100 HOST (26),
101 HOST_LAST ()
102 };
103
104 void
_nss_test2_init_hook(test_tables * t)105 _nss_test2_init_hook(test_tables *t)
106 {
107 t->pwd_table = pwd_table_2;
108 t->host_table = host_table_2;
109 }
110
111 static void
must_be_tests(struct passwd * pt,struct hostent * ht)112 must_be_tests (struct passwd *pt, struct hostent *ht)
113 {
114 int i;
115 struct hostent *h;
116
117 struct passwd *p;
118 for (i = 0; !PWD_ISLAST (&pt[i]); ++i)
119 {
120 p = getpwuid (pt[i].pw_uid);
121 TEST_VERIFY (p != NULL);
122 if (p != NULL)
123 {
124 TEST_VERIFY (strcmp (p->pw_name, pt[i].pw_name) == 0);
125 }
126 }
127
128 setpwent ();
129 for (i = 0; !PWD_ISLAST (&pt[i]); ++i)
130 {
131 p = getpwent ();
132 TEST_VERIFY (p != NULL);
133 if (p != NULL)
134 {
135 TEST_VERIFY (strcmp (p->pw_name, pt[i].pw_name) == 0);
136 TEST_VERIFY (p->pw_uid == pt[i].pw_uid);
137 }
138 }
139 endpwent ();
140
141 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
142 {
143 h = gethostbyname (ht[i].h_name);
144 TEST_VERIFY (h != NULL);
145 if (h != NULL)
146 {
147 TEST_VERIFY (strcmp (h->h_name, ht[i].h_name) == 0);
148 TEST_VERIFY (h->h_addr_list[0] != NULL);
149 if (h->h_addr_list[0])
150 TEST_VERIFY (strcmp (h->h_addr_list[0], ht[i].h_addr_list[0]) == 0);
151 }
152 }
153
154 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
155 {
156 struct hostent r, *rp;
157 char buf[TESTBUFLEN];
158 int herrno, res;
159
160 res = gethostbyname2_r (ht[i].h_name, AF_INET,
161 &r, buf, TESTBUFLEN, &rp, &herrno);
162 TEST_VERIFY (res == 0);
163 if (res == 0)
164 {
165 TEST_VERIFY (strcmp (r.h_name, ht[i].h_name) == 0);
166 TEST_VERIFY (r.h_addr_list[0] != NULL);
167 if (r.h_addr_list[0])
168 TEST_VERIFY (strcmp (r.h_addr_list[0], ht[i].h_addr_list[0]) == 0);
169 }
170 }
171
172 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
173 {
174 h = gethostbyaddr (ht[i].h_addr, 4, AF_INET);
175 TEST_VERIFY (h != NULL);
176 if (h != NULL)
177 {
178 TEST_VERIFY (strcmp (h->h_name, ht[i].h_name) == 0);
179 TEST_VERIFY (h->h_addr_list[0] != NULL);
180 if (h->h_addr_list[0])
181 TEST_VERIFY (strcmp (h->h_addr_list[0], ht[i].h_addr_list[0]) == 0);
182 }
183 }
184
185 /* getaddrinfo */
186
187 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
188 {
189 struct addrinfo *ap;
190 struct addrinfo hint;
191 int res, j;
192
193 memset (&hint, 0, sizeof (hint));
194 hint.ai_family = AF_INET;
195 hint.ai_socktype = SOCK_STREAM;
196 hint.ai_protocol = 0;
197 hint.ai_flags = 0;
198
199 ap = NULL;
200 res = getaddrinfo (ht[i].h_name, NULL, &hint, &ap);
201 TEST_VERIFY (res == 0);
202 TEST_VERIFY (ap != NULL);
203 if (res == 0 && ap != NULL)
204 {
205 j = 0; /* which address in the list */
206 while (ap)
207 {
208 struct sockaddr_in *in = (struct sockaddr_in *)ap->ai_addr;
209 unsigned char *up = (unsigned char *)&in->sin_addr;
210
211 TEST_VERIFY (memcmp (up, ht[i].h_addr_list[j], 4) == 0);
212
213 ap = ap->ai_next;
214 ++j;
215 }
216 }
217 }
218
219 /* getnameinfo */
220
221 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
222 {
223 struct sockaddr_in addr;
224 int res;
225 char host_buf[NI_MAXHOST];
226
227 memset (&addr, 0, sizeof (addr));
228 addr.sin_family = AF_INET;
229 addr.sin_port = 80;
230 memcpy (& addr.sin_addr, ht[i].h_addr_list[0], 4);
231
232 res = getnameinfo ((struct sockaddr *) &addr, sizeof(addr),
233 host_buf, sizeof(host_buf),
234 NULL, 0, NI_NOFQDN);
235
236 TEST_VERIFY (res == 0);
237 if (res == 0)
238 TEST_VERIFY (strcmp (ht[i].h_name, host_buf) == 0);
239 else
240 printf ("error %s\n", gai_strerror (res));
241 }
242 }
243
244 static void
must_be_1(void)245 must_be_1 (void)
246 {
247 struct passwd *p;
248
249 must_be_tests (pwd_table_1, host_table_1);
250 p = getpwnam("name5");
251 TEST_VERIFY (p == NULL);
252 }
253
254 static void
must_be_2(void)255 must_be_2 (void)
256 {
257 struct passwd *p;
258
259 must_be_tests (pwd_table_2, host_table_2);
260 p = getpwnam("name100");
261 TEST_VERIFY (p == NULL);
262 }
263
264 static void
xrename(const char * a,const char * b)265 xrename (const char *a, const char *b)
266 {
267 int i = rename (a, b);
268 if (i != 0)
269 FAIL_EXIT1 ("rename(%s,%s) failed: %s\n", a, b, strerror(errno));
270 }
271
272 /* If the actions change while in the midst of doing a series of
273 lookups, make sure they're consistent. */
274 static void
test_cross_switch_consistency(void)275 test_cross_switch_consistency (void)
276 {
277 int i;
278 struct passwd *p;
279
280 /* We start by initiating a set/get/end loop on conf1. */
281 setpwent ();
282 for (i = 0; !PWD_ISLAST (&pwd_table_1[i]); ++i)
283 {
284 p = getpwent ();
285 TEST_VERIFY (p != NULL);
286 if (p != NULL)
287 {
288 TEST_VERIFY (strcmp (p->pw_name, pwd_table_1[i].pw_name) == 0);
289 TEST_VERIFY (p->pw_uid == pwd_table_1[i].pw_uid);
290 }
291
292 /* After the first lookup, switch to conf2 and verify */
293 if (i == 0)
294 {
295 xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf1");
296 xrename ("/etc/nsswitch.conf2", "/etc/nsswitch.conf");
297
298 p = getpwnam (pwd_table_2[0].pw_name);
299 TEST_VERIFY (p->pw_uid == pwd_table_2[0].pw_uid);
300 }
301
302 /* But the original loop should still be on conf1. */
303 }
304 endpwent ();
305
306 /* Make sure the set/get/end loop sees conf2 now. */
307 setpwent ();
308 for (i = 0; !PWD_ISLAST (&pwd_table_2[i]); ++i)
309 {
310 p = getpwent ();
311 TEST_VERIFY (p != NULL);
312 if (p != NULL)
313 {
314 TEST_VERIFY (strcmp (p->pw_name, pwd_table_2[i].pw_name) == 0);
315 TEST_VERIFY (p->pw_uid == pwd_table_2[i].pw_uid);
316 }
317 }
318 endpwent ();
319
320 }
321
322 static int
do_test(void)323 do_test (void)
324 {
325 /* The test1 module was configured at program start. */
326 must_be_1 ();
327
328 xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf1");
329 xrename ("/etc/nsswitch.conf2", "/etc/nsswitch.conf");
330 must_be_2 ();
331
332 xrename ("/etc/nsswitch.conf", "/etc/nsswitch.conf2");
333 xrename ("/etc/nsswitch.conf1", "/etc/nsswitch.conf");
334 must_be_1 ();
335
336 test_cross_switch_consistency ();
337
338 return 0;
339 }
340
341 #include <support/test-driver.c>
342