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