1/* Test that nsswitch.conf reloading actually works.
2 Copyright (C) 2020-2024 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
35static 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
44static const char *hostaddr_5[] =
45 {
46 "ABCd", "ABCD", "ABC4", NULL
47 };
48
49static const char *hostaddr_15[] =
50 {
51 "4321", "4322", NULL
52 };
53
54static const char *hostaddr_25[] =
55 {
56 "WXYZ", NULL
57 };
58
59
60static struct hostent host_table_1[] = {
61 HOST (5),
62 HOST (15),
63 HOST (25),
64 HOST_LAST ()
65};
66
67void
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. */
75static struct passwd pwd_table_2[] = {
76 PWD (5),
77 PWD_N(200, "name30"),
78 PWD (16),
79 PWD_LAST ()
80 };
81
82static const char *hostaddr_6[] =
83 {
84 "mnop", NULL
85 };
86
87static const char *hostaddr_16[] =
88 {
89 "7890", "7891", NULL
90 };
91
92static const char *hostaddr_26[] =
93 {
94 "qwer", "qweR", NULL
95 };
96
97static struct hostent host_table_2[] = {
98 HOST (6),
99 HOST (16),
100 HOST (26),
101 HOST_LAST ()
102};
103
104void
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
111static void
112must_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 (uid: pt[i].pw_uid);
121 TEST_VERIFY (p != NULL);
122 if (p != NULL)
123 {
124 TEST_COMPARE_STRING (p->pw_name, pt[i].pw_name);
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_COMPARE_STRING (p->pw_name, pt[i].pw_name);
136 TEST_COMPARE (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 (name: ht[i].h_name);
144 TEST_VERIFY (h != NULL);
145 if (h != NULL)
146 {
147 TEST_COMPARE_STRING (h->h_name, ht[i].h_name);
148 TEST_COMPARE (h->h_addrtype, AF_INET);
149 TEST_VERIFY (h->h_addr_list[0] != NULL);
150 if (h->h_addr_list[0] != NULL)
151 TEST_COMPARE_BLOB (h->h_addr_list[0], h->h_length,
152 ht[i].h_addr_list[0], ht[i].h_length);
153 }
154 }
155
156 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
157 {
158 struct hostent r, *rp;
159 char buf[TESTBUFLEN];
160 int herrno, res;
161
162 res = gethostbyname2_r (name: ht[i].h_name, AF_INET,
163 result_buf: &r, buf: buf, TESTBUFLEN, result: &rp, h_errnop: &herrno);
164 TEST_COMPARE (res, 0);
165 if (res == 0)
166 {
167 TEST_COMPARE_STRING (r.h_name, ht[i].h_name);
168 TEST_COMPARE (r.h_addrtype, AF_INET);
169 TEST_VERIFY (r.h_addr_list[0] != NULL);
170 if (r.h_addr_list[0] != NULL)
171 TEST_COMPARE_BLOB (r.h_addr_list[0], r.h_length,
172 ht[i].h_addr_list[0], ht[i].h_length);
173 }
174 }
175
176 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
177 {
178 h = gethostbyaddr (addr: ht[i].h_addr, len: 4, AF_INET);
179 TEST_VERIFY (h != NULL);
180 if (h != NULL)
181 {
182 TEST_COMPARE_STRING (h->h_name, ht[i].h_name);
183 TEST_VERIFY (h->h_addr_list[0] != NULL);
184 if (h->h_addr_list[0] != NULL)
185 TEST_COMPARE_BLOB (h->h_addr_list[0], h->h_length,
186 ht[i].h_addr_list[0], ht[i].h_length);
187 }
188 }
189
190 /* getaddrinfo */
191
192 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
193 {
194 struct addrinfo *ap;
195 struct addrinfo hint;
196 int res, j;
197
198 memset (&hint, 0, sizeof (hint));
199 hint.ai_family = AF_INET;
200 hint.ai_socktype = SOCK_STREAM;
201 hint.ai_protocol = 0;
202 hint.ai_flags = 0;
203
204 ap = NULL;
205 res = getaddrinfo (ht[i].h_name, NULL, &hint, &ap);
206 TEST_COMPARE (res, 0);
207 TEST_VERIFY (ap != NULL);
208 if (res == 0 && ap != NULL)
209 {
210 j = 0; /* which address in the list */
211 while (ap)
212 {
213 TEST_COMPARE (ap->ai_family, AF_INET);
214
215 struct sockaddr_in *in = (struct sockaddr_in *)ap->ai_addr;
216 unsigned char *up = (unsigned char *)&in->sin_addr;
217
218 TEST_COMPARE_BLOB (up, 4, ht[i].h_addr_list[j], 4);
219
220 ap = ap->ai_next;
221 ++j;
222 }
223 }
224 }
225
226 /* getnameinfo */
227
228 for (i = 0; !HOST_ISLAST (&ht[i]); ++i)
229 {
230 struct sockaddr_in addr;
231 int res;
232 char host_buf[NI_MAXHOST];
233
234 memset (&addr, 0, sizeof (addr));
235 addr.sin_family = AF_INET;
236 addr.sin_port = 80;
237 memcpy (& addr.sin_addr, ht[i].h_addr_list[0], 4);
238
239 res = getnameinfo ((struct sockaddr *) &addr, sizeof(addr),
240 host_buf, sizeof(host_buf),
241 NULL, 0, NI_NOFQDN);
242
243 TEST_COMPARE (res, 0);
244 if (res == 0)
245 TEST_VERIFY (strcmp (ht[i].h_name, host_buf) == 0);
246 else
247 printf (format: "error %s\n", gai_strerror (res));
248 }
249}
250
251static void
252must_be_1 (void)
253{
254 struct passwd *p;
255
256 must_be_tests (pt: pwd_table_1, ht: host_table_1);
257 p = getpwnam(name: "name5");
258 TEST_VERIFY (p == NULL);
259}
260
261static void
262must_be_2 (void)
263{
264 struct passwd *p;
265
266 must_be_tests (pt: pwd_table_2, ht: host_table_2);
267 p = getpwnam(name: "name100");
268 TEST_VERIFY (p == NULL);
269}
270
271static void
272xrename (const char *a, const char *b)
273{
274 int i = rename (old: a, new: b);
275 if (i != 0)
276 FAIL_EXIT1 ("rename(%s,%s) failed: %s\n", a, b, strerror(errno));
277}
278
279/* If the actions change while in the midst of doing a series of
280 lookups, make sure they're consistent. */
281static void
282test_cross_switch_consistency (void)
283{
284 int i;
285 struct passwd *p;
286
287 /* We start by initiating a set/get/end loop on conf1. */
288 setpwent ();
289 for (i = 0; !PWD_ISLAST (&pwd_table_1[i]); ++i)
290 {
291 p = getpwent ();
292 TEST_VERIFY (p != NULL);
293 if (p != NULL)
294 {
295 TEST_COMPARE_STRING (p->pw_name, pwd_table_1[i].pw_name);
296 TEST_COMPARE (p->pw_uid, pwd_table_1[i].pw_uid);
297 }
298
299 /* After the first lookup, switch to conf2 and verify */
300 if (i == 0)
301 {
302 xrename (a: "/etc/nsswitch.conf", b: "/etc/nsswitch.conf1");
303 xrename (a: "/etc/nsswitch.conf2", b: "/etc/nsswitch.conf");
304
305 p = getpwnam (name: pwd_table_2[0].pw_name);
306 TEST_COMPARE (p->pw_uid, pwd_table_2[0].pw_uid);
307 }
308
309 /* But the original loop should still be on conf1. */
310 }
311 endpwent ();
312
313 /* Make sure the set/get/end loop sees conf2 now. */
314 setpwent ();
315 for (i = 0; !PWD_ISLAST (&pwd_table_2[i]); ++i)
316 {
317 p = getpwent ();
318 TEST_VERIFY (p != NULL);
319 if (p != NULL)
320 {
321 TEST_COMPARE_STRING (p->pw_name, pwd_table_2[i].pw_name);
322 TEST_COMPARE (p->pw_uid, pwd_table_2[i].pw_uid);
323 }
324 }
325 endpwent ();
326
327}
328
329static int
330do_test (void)
331{
332 /* The test1 module was configured at program start. */
333 must_be_1 ();
334
335 xrename (a: "/etc/nsswitch.conf", b: "/etc/nsswitch.conf1");
336 xrename (a: "/etc/nsswitch.conf2", b: "/etc/nsswitch.conf");
337 must_be_2 ();
338
339 xrename (a: "/etc/nsswitch.conf", b: "/etc/nsswitch.conf2");
340 xrename (a: "/etc/nsswitch.conf1", b: "/etc/nsswitch.conf");
341 must_be_1 ();
342
343 test_cross_switch_consistency ();
344
345 return 0;
346}
347
348#include <support/test-driver.c>
349

source code of glibc/nss/tst-reload1.c