1 /* Common code for NSS test cases.
2    Copyright (C) 2017-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 
20 /* There are two (or more) NSS test modules named nss_test1,
21    nss_test2, etc.  Each one will call a function IN THE TEST CASE
22    called _nss_test1_init_hook(test_tables *) (or _nss_test2_*, etc).
23 
24    In your copy of the hook function, you may change the *_table
25    pointers in the passed struct to point to static tables in your
26    test case, and the test modules will use that table instead.
27 
28    Your tables MUST end with an entry that has a *_LAST() macro.
29    Use the *_ISLAST() macro to test for end of list.
30 
31    Use __nss_configure_lookup("passwd", "test1 test2") (for example) to
32    configure NSS to use the test modules.  */
33 
34 #include <pwd.h>
35 #include <grp.h>
36 #include <shadow.h>
37 #include <netdb.h>
38 
39 typedef struct test_tables {
40   struct passwd *pwd_table;
41   struct group *grp_table;
42   struct spwd *spwd_table;
43   struct hostent *host_table;
44 } test_tables;
45 
46 extern void _nss_test1_init_hook (test_tables *) __attribute__((weak));
47 extern void _nss_test2_init_hook (test_tables *) __attribute__((weak));
48 
49 #define PWD_LAST()    { .pw_name = NULL, .pw_uid = 0 }
50 #define GRP_LAST()    { .gr_name = NULL, .gr_gid = 0 }
51 #define SPWD_LAST()    { .sp_namp = NULL, .sp_pwdp = NULL }
52 #define HOST_LAST()    { .h_name = NULL, .h_aliases = NULL, .h_length = 0, .h_addr_list = NULL }
53 
54 #define PWD_ISLAST(p)    ((p)->pw_name == NULL && (p)->pw_uid == 0)
55 #define GRP_ISLAST(g)    ((g)->gr_name == NULL && (g)->gr_gid == 0)
56 #define SPWD_ISLAST(s)    ((s)->sp_namp == NULL && (s)->sp_pwdp == 0)
57 #define HOST_ISLAST(h)    ((h)->h_name == NULL && (h)->h_length == 0)
58 
59 /* Macros to fill in the tables easily.  */
60 
61 /* Note that the "unparameterized" fields are not magic; they're just
62    arbitrary values.  Tests which need to verify those fields should
63    fill them in explicitly.  */
64 
65 #define PWD(u) \
66     { .pw_name = (char *) "name" #u, .pw_passwd = (char *) "*", .pw_uid = u,  \
67       .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*",	      \
68       .pw_shell = (char *) "*" }
69 
70 #define PWD_N(u,n)								\
71     { .pw_name = (char *) n, .pw_passwd = (char *) "*", .pw_uid = u,  \
72       .pw_gid = 100, .pw_gecos = (char *) "*", .pw_dir = (char *) "*",	      \
73       .pw_shell = (char *) "*" }
74 
75 #define GRP(u) \
76     { .gr_name = (char *) "name" #u, .gr_passwd = (char *) "*", .gr_gid = u, \
77       .gr_mem = (char **) group_##u }
78 
79 #define GRP_N(u,n,m)						     \
80     { .gr_name = (char *) n, .gr_passwd = (char *) "*", .gr_gid = u, \
81       .gr_mem = (char **) m }
82 
83 #define SPWD(u) \
84     { .sp_namp = (char *) "name" #u, .sp_pwdp = (char *) "passwd" #u }
85 
86 #define HOST(u)								\
87     { .h_name = (char *) "name" #u, .h_aliases = NULL, .h_addrtype = u,	\
88       .h_length = 4,							\
89       .h_addr_list = (char **) hostaddr_##u  }
90 
91 /*------------------------------------------------------------*/
92 
93 /* Helper functions for testing passwd entries.  Call
94    compare_passwds() passing a test index, the passwd entry you got,
95    and the expected passwd entry.  The function will return the number
96    of mismatches, or zero of the two records are the same.  */
97 
98 static void __attribute__((used))
print_passwd(struct passwd * p)99 print_passwd (struct passwd *p)
100 {
101   printf ("    passwd %u.%s (%s) :", p->pw_uid, p->pw_name, p->pw_passwd);
102   printf (" %u, %s, %s, %s\n", p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell);
103   printf ("\n");
104 }
105 
106 static int  __attribute__((used))
compare_passwd_field(int i,struct passwd * p,const char * got,const char * exp,const char * name)107 compare_passwd_field (int i, struct passwd *p, const char *got,
108 		      const char *exp, const char *name)
109 {
110   /* Does the entry have a value?  */
111   if (got == NULL)
112     {
113       printf ("[%d] passwd %s for %u.%s was (null)\n",
114 	      i, name,
115 	      p->pw_uid, p->pw_name);
116       return 1;
117     }
118   /* Does the entry have an unexpected name?  */
119   else if (exp == NULL)
120     {
121       printf ("[%d] passwd %s for %u.(null) was %s\n",
122 	      i, name,
123 	      p->pw_uid, got);
124       return 1;
125     }
126   /* And is it correct?  */
127   else if (got && strcmp (got, exp) != 0)
128     {
129       printf("[%d] passwd entry %u.%s had %s \"%s\" (expected \"%s\") \n",
130 	     i,
131 	     p->pw_uid, p->pw_name, name,
132 	     got, exp);
133       return 1;
134     }
135   return 0;
136 }
137 
138 #define COMPARE_PWD_FIELD(f) \
139   retval += compare_passwd_field (i, e, p->f, e->f, #f)
140 
141 /* Compare passwd to expected passwd, return number of "problems".
142    "I" is the index into the testcase data.  */
143 static int  __attribute__((used))
compare_passwds(int i,struct passwd * p,struct passwd * e)144 compare_passwds (int i, struct passwd *p, struct passwd *e)
145 {
146   int retval = 0;
147 
148   /* Did we get the expected uid?  */
149   if (p->pw_uid != e->pw_uid)
150     {
151       printf("[%d] passwd entry %u.%s had uid %u\n", i,
152 	     e->pw_uid, e->pw_name,
153 	     p->pw_uid);
154       ++retval;
155     }
156 
157   /* Did we get the expected gid?  */
158   if (p->pw_gid != e->pw_gid)
159     {
160       printf("[%d] passwd entry %u.%s had gid %u (expected %u)\n", i,
161 	     e->pw_uid, e->pw_name,
162 	     p->pw_gid, e->pw_gid);
163       ++retval;
164     }
165 
166   COMPARE_PWD_FIELD (pw_name);
167   COMPARE_PWD_FIELD (pw_passwd);
168   COMPARE_PWD_FIELD (pw_gecos);
169   COMPARE_PWD_FIELD (pw_dir);
170   COMPARE_PWD_FIELD (pw_shell);
171 
172   if (retval > 0)
173     {
174       /* Left in for debugging later, if needed.  */
175       print_passwd (p);
176       print_passwd (e);
177     }
178 
179   return retval;
180 }
181 
182 /*------------------------------------------------------------*/
183 
184 /* Helpers for checking group entries.  See passwd helper comment
185    above for details.  */
186 
187 static void __attribute__((used))
print_group(struct group * g)188 print_group (struct group *g)
189 {
190   int j;
191 
192   printf ("    group %u.%s (%s) :", g->gr_gid, g->gr_name, g->gr_passwd);
193   if (g->gr_mem)
194     for (j=0; g->gr_mem[j]; j++)
195       printf ("%s%s", j==0 ? " " : ", ", g->gr_mem[j]);
196   printf ("\n");
197 }
198 
199 /* Compare group to expected group, return number of "problems".  "I"
200    is the index into the testcase data.  */
201 static int  __attribute__((used))
compare_groups(int i,struct group * g,struct group * e)202 compare_groups (int i, struct group *g, struct group *e)
203 {
204   int j;
205   int retval = 0;
206 
207   /* Did we get the expected gid?  */
208   if (g->gr_gid != e->gr_gid)
209     {
210       printf("[%d] group entry %u.%s had gid %u\n", i,
211 	     e->gr_gid, e->gr_name,
212 	     g->gr_gid);
213       ++retval;
214     }
215 
216   /* Does the entry have a name?  */
217   if (g->gr_name == NULL)
218     {
219       printf ("[%d] group name for %u.%s was (null)\n", i,
220 	      e->gr_gid, e->gr_name);
221       ++retval;
222     }
223   /* Does the entry have an unexpected name?  */
224   else if (e->gr_name == NULL)
225     {
226       printf ("[%d] group name for %u.(null) was %s\n", i,
227 	      e->gr_gid, g->gr_name);
228       ++retval;
229     }
230   /* And is it correct?  */
231   else if (strcmp (g->gr_name, e->gr_name) != 0)
232     {
233       printf("[%d] group entry %u.%s had name \"%s\"\n", i,
234 	     e->gr_gid, e->gr_name,
235 	     g->gr_name);
236       ++retval;
237     }
238 
239   /* Does the entry have a password?  */
240   if (g->gr_passwd == NULL && e->gr_passwd != NULL)
241     {
242       printf ("[%d] group password for %u.%s was NULL\n", i,
243 	      e->gr_gid, e->gr_name);
244       ++retval;
245     }
246   else if (g->gr_passwd != NULL && e->gr_passwd == NULL)
247     {
248       printf ("[%d] group password for %u.%s was not NULL\n", i,
249 	      e->gr_gid, e->gr_name);
250       ++retval;
251     }
252   /* And is it correct?  */
253   else if (g->gr_passwd && strcmp (g->gr_passwd, e->gr_passwd) != 0)
254     {
255       printf("[%d] group entry %u.%s had password \"%s\" (not \"%s\")\n", i,
256 	     e->gr_gid, e->gr_name,
257 	     g->gr_passwd, e->gr_passwd);
258       ++retval;
259     }
260 
261   /* Now compare group members... */
262 
263   if (e->gr_mem != NULL && g->gr_mem == NULL)
264     {
265       printf("[%d] group entry %u.%s missing member list\n", i,
266 	     e->gr_gid, e->gr_name);
267       ++retval;
268     }
269   else if (e->gr_mem == NULL && g->gr_mem != NULL)
270     {
271       printf("[%d] group entry %u.%s has unexpected member list\n", i,
272 	     e->gr_gid, e->gr_name);
273       ++retval;
274     }
275   else if (e->gr_mem == NULL && g->gr_mem == NULL)
276     {
277       /* This case is OK.  */
278     }
279   else
280     {
281       /* Compare two existing lists.  */
282       j = 0;
283       for (;;)
284 	{
285 	  if (g->gr_mem[j] == NULL && e->gr_mem[j] == NULL)
286 	    {
287 	      /* Matching end-of-lists.  */
288 	      break;
289 	    }
290 	  if (g->gr_mem[j] == NULL)
291 	    {
292 	      printf ("[%d] group member list for %u.%s is too short.\n", i,
293 		      e->gr_gid, e->gr_name);
294 	      ++retval;
295 	      break;
296 	    }
297 	  if (e->gr_mem[j] == NULL)
298 	    {
299 	      printf ("[%d] group member list for %u.%s is too long.\n", i,
300 		      e->gr_gid, e->gr_name);
301 	      ++retval;
302 	      break;
303 	    }
304 	  if (strcmp (g->gr_mem[j], e->gr_mem[j]) != 0)
305 	    {
306 	      printf ("[%d] group member list for %u.%s differs: %s vs %s.\n", i,
307 		      e->gr_gid, e->gr_name,
308 		      e->gr_mem[j], g->gr_mem[j]);
309 	      ++retval;
310 	    }
311 
312 	  j++;
313 	}
314     }
315 
316   if (retval > 0)
317     {
318       /* Left in for debugging later, if needed.  */
319       print_group (g);
320       print_group (e);
321     }
322 
323   return retval;
324 }
325