]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - tools/regression/lib/libc/nss/test-getgr.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / tools / regression / lib / libc / nss / test-getgr.c
1 /*-
2  * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
3  * All rights regrped.
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 <assert.h>
33 #include <errno.h>
34 #include <grp.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stringlist.h>
39 #include <unistd.h>
40 #include "testutil.h"
41
42 enum test_methods {
43         TEST_GETGRENT,
44         TEST_GETGRNAM,
45         TEST_GETGRGID,
46         TEST_GETGRENT_2PASS,
47         TEST_BUILD_SNAPSHOT
48 };
49
50 static int debug = 0;
51 static enum test_methods method = TEST_BUILD_SNAPSHOT;
52
53 DECLARE_TEST_DATA(group)
54 DECLARE_TEST_FILE_SNAPSHOT(group)
55 DECLARE_1PASS_TEST(group)
56 DECLARE_2PASS_TEST(group)
57
58 static void clone_group(struct group *, struct group const *);
59 static int compare_group(struct group *, struct group *, void *);
60 static void dump_group(struct group *);
61 static void free_group(struct group *);
62
63 static void sdump_group(struct group *, char *, size_t);
64 static int group_read_snapshot_func(struct group *, char *);
65
66 static int group_check_ambiguity(struct group_test_data *, 
67         struct group *);
68 static int group_fill_test_data(struct group_test_data *);
69 static int group_test_correctness(struct group *, void *);
70 static int group_test_getgrnam(struct group *, void *);
71 static int group_test_getgrgid(struct group *, void *);
72 static int group_test_getgrent(struct group *, void *);
73         
74 static void usage(void)  __attribute__((__noreturn__));
75
76 IMPLEMENT_TEST_DATA(group)
77 IMPLEMENT_TEST_FILE_SNAPSHOT(group)
78 IMPLEMENT_1PASS_TEST(group)
79 IMPLEMENT_2PASS_TEST(group)
80
81 static void
82 clone_group(struct group *dest, struct group const *src)
83 {
84         assert(dest != NULL);
85         assert(src != NULL);
86         
87         char **cp;
88         int members_num;
89                 
90         memset(dest, 0, sizeof(struct group));
91         
92         if (src->gr_name != NULL) {
93                 dest->gr_name = strdup(src->gr_name);
94                 assert(dest->gr_name != NULL);
95         }
96         
97         if (src->gr_passwd != NULL) {
98                 dest->gr_passwd = strdup(src->gr_passwd);
99                 assert(dest->gr_passwd != NULL);
100         }
101         dest->gr_gid = src->gr_gid;
102         
103         if (src->gr_mem != NULL) {
104                 members_num = 0;
105                 for (cp = src->gr_mem; *cp; ++cp)
106                         ++members_num;
107         
108                 dest->gr_mem = (char **)malloc(
109                         (members_num + 1) * (sizeof(char *)));
110                 assert(dest->gr_mem != NULL);
111                 memset(dest->gr_mem, 0, (members_num+1) * (sizeof(char *)));
112         
113                 for (cp = src->gr_mem; *cp; ++cp) {
114                         dest->gr_mem[cp - src->gr_mem] = strdup(*cp);
115                         assert(dest->gr_mem[cp - src->gr_mem] != NULL);
116                 }
117         }
118 }
119
120 static void 
121 free_group(struct group *grp)
122 {
123         char **cp;
124         
125         assert(grp != NULL);
126         
127         free(grp->gr_name);
128         free(grp->gr_passwd);
129         
130         for (cp = grp->gr_mem; *cp; ++cp)
131                 free(*cp);
132         free(grp->gr_mem);
133 }
134
135 static  int 
136 compare_group(struct group *grp1, struct group *grp2, void *mdata)
137 {
138         char **c1, **c2;
139         
140         if (grp1 == grp2)
141                 return (0);
142         
143         if ((grp1 == NULL) || (grp2 == NULL))
144                 goto errfin;
145         
146         if ((strcmp(grp1->gr_name, grp2->gr_name) != 0) ||
147                 (strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0) ||
148                 (grp1->gr_gid != grp2->gr_gid))
149                         goto errfin;
150         
151         c1 = grp1->gr_mem;
152         c2 = grp2->gr_mem;
153         
154         if ((grp1->gr_mem == NULL) || (grp2->gr_mem == NULL))
155                 goto errfin;
156         
157         for (;*c1 && *c2; ++c1, ++c2)
158                 if (strcmp(*c1, *c2) != 0)
159                         goto errfin;
160                 
161         if ((*c1 != '\0') || (*c2 != '\0'))
162                 goto errfin;
163         
164         return 0;
165         
166 errfin:
167         if ((debug) && (mdata == NULL)) {
168                 printf("following structures are not equal:\n");
169                 dump_group(grp1);
170                 dump_group(grp2);
171         }
172
173         return (-1);
174 }
175
176 static void
177 sdump_group(struct group *grp, char *buffer, size_t buflen)
178 {
179         char **cp;
180         int written;
181         
182         written = snprintf(buffer, buflen, "%s %s %d",
183                 grp->gr_name, grp->gr_passwd, grp->gr_gid);     
184         buffer += written;
185         if (written > buflen)
186                 return;
187         buflen -= written;
188                         
189         if (grp->gr_mem != NULL) {
190                 if (*(grp->gr_mem) != '\0') {
191                         for (cp = grp->gr_mem; *cp; ++cp) {
192                                 written = snprintf(buffer, buflen, " %s",*cp);
193                                 buffer += written;
194                                 if (written > buflen)
195                                         return;
196                                 buflen -= written;
197                                 
198                                 if (buflen == 0)
199                                         return;                         
200                         }
201                 } else
202                         snprintf(buffer, buflen, " nomem");
203         } else
204                 snprintf(buffer, buflen, " (null)");
205 }
206
207 static int
208 group_read_snapshot_func(struct group *grp, char *line)
209 {
210         StringList *sl;
211         char *s, *ps, *ts;
212         int i;
213
214         if (debug)
215                 printf("1 line read from snapshot:\n%s\n", line);
216         
217         i = 0;
218         sl = NULL;
219         ps = line;
220         memset(grp, 0, sizeof(struct group));
221         while ( (s = strsep(&ps, " ")) != NULL) {
222                 switch (i) {
223                         case 0:
224                                 grp->gr_name = strdup(s);
225                                 assert(grp->gr_name != NULL);
226                         break;
227
228                         case 1:
229                                 grp->gr_passwd = strdup(s);
230                                 assert(grp->gr_passwd != NULL);
231                         break;
232
233                         case 2:
234                                 grp->gr_gid = (gid_t)strtol(s, &ts, 10);
235                                 if (*ts != '\0') {
236                                         free(grp->gr_name);
237                                         free(grp->gr_passwd);
238                                         return (-1);
239                                 }
240                         break;
241
242                         default:
243                                 if (sl == NULL) {
244                                         if (strcmp(s, "(null)") == 0)
245                                                 return (0);
246                                                                                 
247                                         sl = sl_init();
248                                         assert(sl != NULL);
249                                         
250                                         if (strcmp(s, "nomem") != 0) {
251                                                 ts = strdup(s);
252                                                 assert(ts != NULL);
253                                                 sl_add(sl, ts);
254                                         }
255                                 } else {
256                                         ts = strdup(s);
257                                         assert(ts != NULL);
258                                         sl_add(sl, ts);
259                                 }
260                         break;                  
261                 };
262                 ++i;
263         }
264
265         if (i < 3) {
266                 free(grp->gr_name);
267                 free(grp->gr_passwd);
268                 memset(grp, 0, sizeof(struct group));
269                 return (-1);
270         }
271         
272         sl_add(sl, NULL);
273         grp->gr_mem = sl->sl_str;
274
275         /* NOTE: is it a dirty hack or not? */
276         free(sl);       
277         return (0);
278 }
279
280 static void 
281 dump_group(struct group *result)
282 {
283         if (result != NULL) {
284                 char buffer[1024];
285                 sdump_group(result, buffer, sizeof(buffer));
286                 printf("%s\n", buffer);
287         } else
288                 printf("(null)\n");
289 }
290
291 static int
292 group_fill_test_data(struct group_test_data *td)
293 {
294         struct group *grp;
295                 
296         setgroupent(1);
297         while ((grp = getgrent()) != NULL) {
298                 if (group_test_correctness(grp, NULL) == 0)
299                         TEST_DATA_APPEND(group, td, grp);
300                 else
301                         return (-1);
302         }
303         endgrent();
304         
305         return (0);
306 }
307
308 static int
309 group_test_correctness(struct group *grp, void *mdata)
310 {
311         if (debug) {
312                 printf("testing correctness with the following data:\n");
313                 dump_group(grp);
314         }
315         
316         if (grp == NULL)
317                 goto errfin;
318         
319         if (grp->gr_name == NULL)
320                 goto errfin;
321         
322         if (grp->gr_passwd == NULL)
323                 goto errfin;
324         
325         if (grp->gr_mem == NULL)
326                 goto errfin;
327         
328         if (debug)
329                 printf("correct\n");
330         
331         return (0);     
332 errfin:
333         if (debug)
334                 printf("incorrect\n");
335         
336         return (-1);
337 }
338
339 /* group_check_ambiguity() is needed here because when doing the getgrent()
340  * calls sequence, records from different nsswitch sources can be different, 
341  * though having the same pw_name/pw_uid */
342 static int
343 group_check_ambiguity(struct group_test_data *td, struct group *pwd)
344 {
345         
346         return (TEST_DATA_FIND(group, td, pwd, compare_group,
347                 NULL) != NULL ? 0 : -1);
348 }
349
350 static int
351 group_test_getgrnam(struct group *grp_model, void *mdata)
352 {
353         struct group *grp;
354                 
355         if (debug) {
356                 printf("testing getgrnam() with the following data:\n");
357                 dump_group(grp_model);
358         }
359
360         grp = getgrnam(grp_model->gr_name);
361         if (group_test_correctness(grp, NULL) != 0)
362                 goto errfin;
363         
364         if ((compare_group(grp, grp_model, NULL) != 0) &&
365             (group_check_ambiguity((struct group_test_data *)mdata, grp) 
366             !=0))
367             goto errfin;
368                 
369         if (debug)
370                 printf("ok\n");
371         return (0);
372         
373 errfin:
374         if (debug)
375                 printf("not ok\n");
376         
377         return (-1);
378 }
379
380 static int
381 group_test_getgrgid(struct group *grp_model, void *mdata)
382 {
383         struct group *grp;
384                 
385         if (debug) {
386                 printf("testing getgrgid() with the following data...\n");
387                 dump_group(grp_model);
388         }       
389         
390         grp = getgrgid(grp_model->gr_gid);
391         if ((group_test_correctness(grp, NULL) != 0) || 
392             ((compare_group(grp, grp_model, NULL) != 0) &&
393             (group_check_ambiguity((struct group_test_data *)mdata, grp)
394             != 0))) {
395             if (debug)
396                 printf("not ok\n");
397             return (-1);
398         } else {
399             if (debug)
400                 printf("ok\n");
401             return (0);
402         }
403 }
404
405 static int 
406 group_test_getgrent(struct group *grp, void *mdata)
407 {
408         /* Only correctness can be checked when doing 1-pass test for
409          * getgrent(). */
410         return (group_test_correctness(grp, NULL));
411 }
412
413 static void
414 usage(void)
415 {
416         (void)fprintf(stderr,
417             "Usage: %s -nge2 [-d] [-s <file>]\n",
418             getprogname());
419         exit(1);
420 }
421
422 int
423 main(int argc, char **argv)
424 {
425         struct group_test_data td, td_snap, td_2pass;
426         char *snapshot_file;
427         int rv;
428         int c;
429         
430         if (argc < 2)
431                 usage();
432                 
433         snapshot_file = NULL;
434         while ((c = getopt(argc, argv, "nge2ds:")) != -1)
435                 switch (c) {
436                 case 'd':
437                         debug++;
438                         break;
439                 case 'n':
440                         method = TEST_GETGRNAM;
441                         break;
442                 case 'g':
443                         method = TEST_GETGRGID;
444                         break;
445                 case 'e':
446                         method = TEST_GETGRENT;
447                         break;
448                 case '2':
449                         method = TEST_GETGRENT_2PASS;
450                         break;
451                 case 's':
452                         snapshot_file = strdup(optarg);
453                         break;
454                 default:
455                         usage();
456                 }
457         
458         TEST_DATA_INIT(group, &td, clone_group, free_group);
459         TEST_DATA_INIT(group, &td_snap, clone_group, free_group);
460         if (snapshot_file != NULL) {
461                 if (access(snapshot_file, W_OK | R_OK) != 0) {          
462                         if (errno == ENOENT)
463                                 method = TEST_BUILD_SNAPSHOT;
464                         else {
465                                 if (debug)
466                                         printf("can't access the file %s\n",
467                                 snapshot_file);
468                         
469                                 rv = -1;
470                                 goto fin;
471                         }
472                 } else {
473                         if (method == TEST_BUILD_SNAPSHOT) {
474                                 rv = 0;
475                                 goto fin;
476                         }
477                         
478                         TEST_SNAPSHOT_FILE_READ(group, snapshot_file,
479                                 &td_snap, group_read_snapshot_func);
480                 }
481         }
482                 
483         rv = group_fill_test_data(&td);
484         if (rv == -1)
485                 return (-1);
486         switch (method) {
487         case TEST_GETGRNAM:
488                 if (snapshot_file == NULL)
489                         rv = DO_1PASS_TEST(group, &td,
490                                 group_test_getgrnam, (void *)&td);
491                 else
492                         rv = DO_1PASS_TEST(group, &td_snap, 
493                                 group_test_getgrnam, (void *)&td_snap);
494                 break;
495         case TEST_GETGRGID:
496                 if (snapshot_file == NULL)
497                         rv = DO_1PASS_TEST(group, &td,
498                                 group_test_getgrgid, (void *)&td);
499                 else
500                         rv = DO_1PASS_TEST(group, &td_snap, 
501                                 group_test_getgrgid, (void *)&td_snap);
502                 break;
503         case TEST_GETGRENT:
504                 if (snapshot_file == NULL)
505                         rv = DO_1PASS_TEST(group, &td, group_test_getgrent,
506                                 (void *)&td);
507                 else
508                         rv = DO_2PASS_TEST(group, &td, &td_snap,
509                                 compare_group, NULL);
510                 break;
511         case TEST_GETGRENT_2PASS:
512                         TEST_DATA_INIT(group, &td_2pass, clone_group, free_group);
513                         rv = group_fill_test_data(&td_2pass);                   
514                         if (rv != -1)
515                                 rv = DO_2PASS_TEST(group, &td, &td_2pass,
516                                         compare_group, NULL);
517                         TEST_DATA_DESTROY(group, &td_2pass);
518                 break;
519         case TEST_BUILD_SNAPSHOT:
520                 if (snapshot_file != NULL)
521                     rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td, 
522                         sdump_group);
523                 break;
524         default:
525                 rv = 0;
526                 break;
527         };
528
529 fin:
530         TEST_DATA_DESTROY(group, &td_snap);
531         TEST_DATA_DESTROY(group, &td);
532         free(snapshot_file);    
533         return (rv);
534 }