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