]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - lib/libc/tests/nss/getgr_test.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / lib / libc / tests / nss / getgr_test.c
1 /*-
2  * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <arpa/inet.h>
32 #include <errno.h>
33 #include <grp.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stringlist.h>
38 #include <unistd.h>
39
40 #include <atf-c.h>
41
42 #include "testutil.h"
43
44 enum test_methods {
45         TEST_GETGRENT = 1,
46         TEST_GETGRNAM = 2,
47         TEST_GETGRGID = 4,
48         TEST_GETGRENT_2PASS = 8,
49         TEST_BUILD_SNAPSHOT = 16,
50 };
51
52 DECLARE_TEST_DATA(group)
53 DECLARE_TEST_FILE_SNAPSHOT(group)
54 DECLARE_1PASS_TEST(group)
55 DECLARE_2PASS_TEST(group)
56
57 static void clone_group(struct group *, struct group const *);
58 static int compare_group(struct group *, struct group *, void *);
59 static void dump_group(struct group *);
60 static void free_group(struct group *);
61
62 static void sdump_group(struct group *, char *, size_t);
63 static int group_read_snapshot_func(struct group *, char *);
64
65 static int group_check_ambiguity(struct group_test_data *,
66         struct group *);
67 static int group_fill_test_data(struct group_test_data *);
68 static int group_test_correctness(struct group *, void *);
69 static int group_test_getgrnam(struct group *, void *);
70 static int group_test_getgrgid(struct group *, void *);
71 static int group_test_getgrent(struct group *, void *);
72
73 IMPLEMENT_TEST_DATA(group)
74 IMPLEMENT_TEST_FILE_SNAPSHOT(group)
75 IMPLEMENT_1PASS_TEST(group)
76 IMPLEMENT_2PASS_TEST(group)
77
78 static void
79 clone_group(struct group *dest, struct group const *src)
80 {
81         ATF_REQUIRE(dest != NULL);
82         ATF_REQUIRE(src != NULL);
83
84         char **cp;
85         int members_num;
86
87         memset(dest, 0, sizeof(struct group));
88
89         if (src->gr_name != NULL) {
90                 dest->gr_name = strdup(src->gr_name);
91                 ATF_REQUIRE(dest->gr_name != NULL);
92         }
93
94         if (src->gr_passwd != NULL) {
95                 dest->gr_passwd = strdup(src->gr_passwd);
96                 ATF_REQUIRE(dest->gr_passwd != NULL);
97         }
98         dest->gr_gid = src->gr_gid;
99
100         if (src->gr_mem != NULL) {
101                 members_num = 0;
102                 for (cp = src->gr_mem; *cp; ++cp)
103                         ++members_num;
104
105                 dest->gr_mem = calloc(members_num + 1, sizeof(char *));
106                 ATF_REQUIRE(dest->gr_mem != NULL);
107
108                 for (cp = src->gr_mem; *cp; ++cp) {
109                         dest->gr_mem[cp - src->gr_mem] = strdup(*cp);
110                         ATF_REQUIRE(dest->gr_mem[cp - src->gr_mem] != NULL);
111                 }
112         }
113 }
114
115 static void
116 free_group(struct group *grp)
117 {
118         char **cp;
119
120         ATF_REQUIRE(grp != NULL);
121
122         free(grp->gr_name);
123         free(grp->gr_passwd);
124
125         for (cp = grp->gr_mem; *cp; ++cp)
126                 free(*cp);
127         free(grp->gr_mem);
128 }
129
130 static  int
131 compare_group(struct group *grp1, struct group *grp2, void *mdata)
132 {
133         char **c1, **c2;
134
135         if (grp1 == grp2)
136                 return (0);
137
138         if (grp1 == NULL || grp2 == NULL)
139                 goto errfin;
140
141         if (strcmp(grp1->gr_name, grp2->gr_name) != 0 ||
142             strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0 ||
143             grp1->gr_gid != grp2->gr_gid)
144                         goto errfin;
145
146         c1 = grp1->gr_mem;
147         c2 = grp2->gr_mem;
148
149         if (grp1->gr_mem == NULL || grp2->gr_mem == NULL)
150                 goto errfin;
151
152         for (; *c1 && *c2; ++c1, ++c2)
153                 if (strcmp(*c1, *c2) != 0)
154                         goto errfin;
155
156         if (*c1 != '\0' || *c2 != '\0')
157                 goto errfin;
158
159         return 0;
160
161 errfin:
162         if (mdata == NULL) {
163                 printf("following structures are not equal:\n");
164                 dump_group(grp1);
165                 dump_group(grp2);
166         }
167
168         return (-1);
169 }
170
171 static void
172 sdump_group(struct group *grp, char *buffer, size_t buflen)
173 {
174         char **cp;
175         int written;
176
177         written = snprintf(buffer, buflen, "%s %s %d",
178                 grp->gr_name, grp->gr_passwd, grp->gr_gid);
179         buffer += written;
180         if (written > (int)buflen)
181                 return;
182         buflen -= written;
183
184         if (grp->gr_mem != NULL) {
185                 if (*(grp->gr_mem) != '\0') {
186                         for (cp = grp->gr_mem; *cp; ++cp) {
187                                 written = snprintf(buffer, buflen, " %s",*cp);
188                                 buffer += written;
189                                 if (written > (int)buflen)
190                                         return;
191                                 buflen -= written;
192
193                                 if (buflen == 0)
194                                         return;
195                         }
196                 } else
197                         snprintf(buffer, buflen, " nomem");
198         } else
199                 snprintf(buffer, buflen, " (null)");
200 }
201
202 static int
203 group_read_snapshot_func(struct group *grp, char *line)
204 {
205         StringList *sl;
206         char *s, *ps, *ts;
207         int i;
208
209         printf("1 line read from snapshot:\n%s\n", line);
210
211         i = 0;
212         sl = NULL;
213         ps = line;
214         memset(grp, 0, sizeof(struct group));
215         while ((s = strsep(&ps, " ")) != NULL) {
216                 switch (i) {
217                 case 0:
218                         grp->gr_name = strdup(s);
219                         ATF_REQUIRE(grp->gr_name != NULL);
220                         break;
221
222                 case 1:
223                         grp->gr_passwd = strdup(s);
224                         ATF_REQUIRE(grp->gr_passwd != NULL);
225                         break;
226
227                 case 2:
228                         grp->gr_gid = (gid_t)strtol(s, &ts, 10);
229                         if (*ts != '\0') {
230                                 free(grp->gr_name);
231                                 free(grp->gr_passwd);
232                                 grp->gr_name = NULL;
233                                 grp->gr_passwd = NULL;
234                                 return (-1);
235                         }
236                         break;
237
238                 default:
239                         if (sl == NULL) {
240                                 if (strcmp(s, "(null)") == 0)
241                                         return (0);
242
243                                 sl = sl_init();
244                                 ATF_REQUIRE(sl != NULL);
245
246                                 if (strcmp(s, "nomem") != 0) {
247                                         ts = strdup(s);
248                                         ATF_REQUIRE(ts != NULL);
249                                         sl_add(sl, ts);
250                                 }
251                         } else {
252                                 ts = strdup(s);
253                                 ATF_REQUIRE(ts != NULL);
254                                 sl_add(sl, ts);
255                         }
256                         break;
257                 }
258                 ++i;
259         }
260
261         if (i < 3) {
262                 free(grp->gr_name);
263                 free(grp->gr_passwd);
264                 memset(grp, 0, sizeof(struct group));
265                 return (-1);
266         }
267
268         sl_add(sl, NULL);
269         grp->gr_mem = sl->sl_str;
270
271         /* NOTE: is it a dirty hack or not? */
272         free(sl);
273         return (0);
274 }
275
276 static void
277 dump_group(struct group *result)
278 {
279         if (result != NULL) {
280                 char buffer[1024];
281                 sdump_group(result, buffer, sizeof(buffer));
282                 printf("%s\n", buffer);
283         } else
284                 printf("(null)\n");
285 }
286
287 static int
288 group_fill_test_data(struct group_test_data *td)
289 {
290         struct group *grp;
291
292         setgroupent(1);
293         while ((grp = getgrent()) != NULL) {
294                 if (group_test_correctness(grp, NULL) == 0)
295                         TEST_DATA_APPEND(group, td, grp);
296                 else
297                         return (-1);
298         }
299         endgrent();
300
301         return (0);
302 }
303
304 static int
305 group_test_correctness(struct group *grp, void *mdata __unused)
306 {
307         printf("testing correctness with the following data:\n");
308         dump_group(grp);
309
310         if (grp == NULL)
311                 goto errfin;
312
313         if (grp->gr_name == NULL)
314                 goto errfin;
315
316         if (grp->gr_passwd == NULL)
317                 goto errfin;
318
319         if (grp->gr_mem == NULL)
320                 goto errfin;
321
322         printf("correct\n");
323
324         return (0);
325 errfin:
326         printf("incorrect\n");
327
328         return (-1);
329 }
330
331 /* group_check_ambiguity() is needed here because when doing the getgrent()
332  * calls sequence, records from different nsswitch sources can be different,
333  * though having the same pw_name/pw_uid */
334 static int
335 group_check_ambiguity(struct group_test_data *td, struct group *pwd)
336 {
337
338         return (TEST_DATA_FIND(group, td, pwd, compare_group,
339                 NULL) != NULL ? 0 : -1);
340 }
341
342 static int
343 group_test_getgrnam(struct group *grp_model, void *mdata)
344 {
345         struct group *grp;
346
347         printf("testing getgrnam() with the following data:\n");
348         dump_group(grp_model);
349
350         grp = getgrnam(grp_model->gr_name);
351         if (group_test_correctness(grp, NULL) != 0)
352                 goto errfin;
353
354         if (compare_group(grp, grp_model, NULL) != 0 &&
355             group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)
356             goto errfin;
357
358         return (0);
359
360 errfin:
361         return (-1);
362 }
363
364 static int
365 group_test_getgrgid(struct group *grp_model, void *mdata)
366 {
367         struct group *grp;
368
369         printf("testing getgrgid() with the following data...\n");
370         dump_group(grp_model);
371
372         grp = getgrgid(grp_model->gr_gid);
373         if (group_test_correctness(grp, NULL) != 0 ||
374             (compare_group(grp, grp_model, NULL) != 0 &&
375              group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)) {
376                 return (-1);
377         } else {
378                 return (0);
379         }
380 }
381
382 static int
383 group_test_getgrent(struct group *grp, void *mdata __unused)
384 {
385         /* Only correctness can be checked when doing 1-pass test for
386          * getgrent(). */
387         return (group_test_correctness(grp, NULL));
388 }
389
390 static int
391 run_tests(const char *snapshot_file, enum test_methods method)
392 {
393         struct group_test_data td, td_snap, td_2pass;
394         int rv;
395
396         TEST_DATA_INIT(group, &td, clone_group, free_group);
397         TEST_DATA_INIT(group, &td_snap, clone_group, free_group);
398         if (snapshot_file != NULL) {
399                 if (access(snapshot_file, W_OK | R_OK) != 0) {
400                         if (errno == ENOENT)
401                                 method = TEST_BUILD_SNAPSHOT;
402                         else {
403                                 printf("can't access the file %s\n",
404                                     snapshot_file);
405
406                                 rv = -1;
407                                 goto fin;
408                         }
409                 } else {
410                         if (method == TEST_BUILD_SNAPSHOT) {
411                                 rv = 0;
412                                 goto fin;
413                         }
414
415                         TEST_SNAPSHOT_FILE_READ(group, snapshot_file,
416                                 &td_snap, group_read_snapshot_func);
417                 }
418         }
419
420         rv = group_fill_test_data(&td);
421         if (rv == -1)
422                 return (-1);
423         switch (method) {
424         case TEST_GETGRNAM:
425                 if (snapshot_file == NULL)
426                         rv = DO_1PASS_TEST(group, &td,
427                                 group_test_getgrnam, (void *)&td);
428                 else
429                         rv = DO_1PASS_TEST(group, &td_snap,
430                                 group_test_getgrnam, (void *)&td_snap);
431                 break;
432         case TEST_GETGRGID:
433                 if (snapshot_file == NULL)
434                         rv = DO_1PASS_TEST(group, &td,
435                                 group_test_getgrgid, (void *)&td);
436                 else
437                         rv = DO_1PASS_TEST(group, &td_snap,
438                                 group_test_getgrgid, (void *)&td_snap);
439                 break;
440         case TEST_GETGRENT:
441                 if (snapshot_file == NULL)
442                         rv = DO_1PASS_TEST(group, &td, group_test_getgrent,
443                                 (void *)&td);
444                 else
445                         rv = DO_2PASS_TEST(group, &td, &td_snap,
446                                 compare_group, NULL);
447                 break;
448         case TEST_GETGRENT_2PASS:
449                         TEST_DATA_INIT(group, &td_2pass, clone_group, free_group);
450                         rv = group_fill_test_data(&td_2pass);
451                         if (rv != -1)
452                                 rv = DO_2PASS_TEST(group, &td, &td_2pass,
453                                         compare_group, NULL);
454                         TEST_DATA_DESTROY(group, &td_2pass);
455                 break;
456         case TEST_BUILD_SNAPSHOT:
457                 if (snapshot_file != NULL)
458                         rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td,
459                             sdump_group);
460                 break;
461         default:
462                 rv = 0;
463                 break;
464         }
465
466 fin:
467         TEST_DATA_DESTROY(group, &td_snap);
468         TEST_DATA_DESTROY(group, &td);
469
470         return (rv);
471 }
472
473 #define SNAPSHOT_FILE   "snapshot_grp"
474
475 ATF_TC_WITHOUT_HEAD(getgrent);
476 ATF_TC_BODY(getgrent, tc)
477 {
478
479         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0);
480 }
481
482 ATF_TC_WITHOUT_HEAD(getgrent_with_snapshot);
483 ATF_TC_BODY(getgrent_with_snapshot, tc)
484 {
485
486         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
487         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0);
488 }
489
490 ATF_TC_WITHOUT_HEAD(getgrent_with_two_pass);
491 ATF_TC_BODY(getgrent_with_two_pass, tc)
492 {
493
494         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT_2PASS) == 0);
495 }
496
497 ATF_TC_WITHOUT_HEAD(getgrgid);
498 ATF_TC_BODY(getgrgid, tc)
499 {
500
501         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0);
502 }
503
504 ATF_TC_WITHOUT_HEAD(getgrgid_with_snapshot);
505 ATF_TC_BODY(getgrgid_with_snapshot, tc)
506 {
507
508         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
509         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0);
510 }
511
512 ATF_TC_WITHOUT_HEAD(getgrnam);
513 ATF_TC_BODY(getgrnam, tc)
514 {
515
516         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0);
517 }
518
519 ATF_TC_WITHOUT_HEAD(getgrnam_with_snapshot);
520 ATF_TC_BODY(getgrnam_with_snapshot, tc)
521 {
522
523         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
524         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0);
525 }
526
527 ATF_TP_ADD_TCS(tp)
528 {
529
530         ATF_TP_ADD_TC(tp, getgrent);
531         ATF_TP_ADD_TC(tp, getgrent_with_snapshot);
532         ATF_TP_ADD_TC(tp, getgrent_with_two_pass);
533         ATF_TP_ADD_TC(tp, getgrgid);
534         ATF_TP_ADD_TC(tp, getgrgid_with_snapshot);
535         ATF_TP_ADD_TC(tp, getgrnam);
536         ATF_TP_ADD_TC(tp, getgrnam_with_snapshot);
537
538         return (atf_no_error());
539 }