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