Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/nss/getgr_test.c
39500 views
1
/*-
2
* Copyright (c) 2006 Michael Bushkov <[email protected]>
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 <arpa/inet.h>
29
#include <errno.h>
30
#include <grp.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <stringlist.h>
35
#include <unistd.h>
36
37
#include <atf-c.h>
38
39
#include "testutil.h"
40
41
enum test_methods {
42
TEST_GETGRENT,
43
TEST_GETGRNAM,
44
TEST_GETGRGID,
45
TEST_GETGRENT_2PASS,
46
TEST_GETGRENT_INTERLEAVED_GETGRNAM,
47
TEST_GETGRENT_INTERLEAVED_GETGRGID,
48
TEST_BUILD_SNAPSHOT,
49
};
50
51
DECLARE_TEST_DATA(group)
52
DECLARE_TEST_FILE_SNAPSHOT(group)
53
DECLARE_1PASS_TEST(group)
54
DECLARE_2PASS_TEST(group)
55
56
static void clone_group(struct group *, struct group const *);
57
static int compare_group(struct group *, struct group *, void *);
58
static void dump_group(struct group *);
59
static void free_group(struct group *);
60
61
static void sdump_group(struct group *, char *, size_t);
62
static int group_read_snapshot_func(struct group *, char *);
63
64
static int group_check_ambiguity(struct group_test_data *, struct group *);
65
static int group_fill_test_data(struct group_test_data *,
66
int (*cb)(struct group *, void *));
67
static int group_test_correctness(struct group *, void *);
68
static int group_test_getgrnam(struct group *, void *);
69
static int group_test_getgrgid(struct group *, void *);
70
static int group_test_getgrent(struct group *, void *);
71
72
IMPLEMENT_TEST_DATA(group)
73
IMPLEMENT_TEST_FILE_SNAPSHOT(group)
74
IMPLEMENT_1PASS_TEST(group)
75
IMPLEMENT_2PASS_TEST(group)
76
77
static void
78
clone_group(struct group *dest, struct group const *src)
79
{
80
ATF_REQUIRE(dest != NULL);
81
ATF_REQUIRE(src != NULL);
82
83
char **cp;
84
int members_num;
85
86
memset(dest, 0, sizeof(struct group));
87
88
if (src->gr_name != NULL) {
89
dest->gr_name = strdup(src->gr_name);
90
ATF_REQUIRE(dest->gr_name != NULL);
91
}
92
93
if (src->gr_passwd != NULL) {
94
dest->gr_passwd = strdup(src->gr_passwd);
95
ATF_REQUIRE(dest->gr_passwd != NULL);
96
}
97
dest->gr_gid = src->gr_gid;
98
99
if (src->gr_mem != NULL) {
100
members_num = 0;
101
for (cp = src->gr_mem; *cp; ++cp)
102
++members_num;
103
104
dest->gr_mem = calloc(members_num + 1, sizeof(char *));
105
ATF_REQUIRE(dest->gr_mem != NULL);
106
107
for (cp = src->gr_mem; *cp; ++cp) {
108
dest->gr_mem[cp - src->gr_mem] = strdup(*cp);
109
ATF_REQUIRE(dest->gr_mem[cp - src->gr_mem] != NULL);
110
}
111
}
112
}
113
114
static void
115
free_group(struct group *grp)
116
{
117
char **cp;
118
119
ATF_REQUIRE(grp != NULL);
120
121
free(grp->gr_name);
122
free(grp->gr_passwd);
123
124
for (cp = grp->gr_mem; *cp; ++cp)
125
free(*cp);
126
free(grp->gr_mem);
127
}
128
129
static int
130
compare_group(struct group *grp1, struct group *grp2, void *mdata)
131
{
132
char **c1, **c2;
133
134
if (grp1 == grp2)
135
return (0);
136
137
if (grp1 == NULL || grp2 == NULL)
138
goto errfin;
139
140
if (strcmp(grp1->gr_name, grp2->gr_name) != 0 ||
141
strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0 ||
142
grp1->gr_gid != grp2->gr_gid)
143
goto errfin;
144
145
c1 = grp1->gr_mem;
146
c2 = grp2->gr_mem;
147
148
if (grp1->gr_mem == NULL || grp2->gr_mem == NULL)
149
goto errfin;
150
151
for (; *c1 && *c2; ++c1, ++c2)
152
if (strcmp(*c1, *c2) != 0)
153
goto errfin;
154
155
if (*c1 != NULL || *c2 != NULL)
156
goto errfin;
157
158
return 0;
159
160
errfin:
161
if (mdata == NULL) {
162
printf("following structures are not equal:\n");
163
dump_group(grp1);
164
dump_group(grp2);
165
}
166
167
return (-1);
168
}
169
170
static void
171
sdump_group(struct group *grp, char *buffer, size_t buflen)
172
{
173
char **cp;
174
int written;
175
176
written = snprintf(buffer, buflen, "%s:%s:%d:",
177
grp->gr_name, grp->gr_passwd, grp->gr_gid);
178
buffer += written;
179
if (written > (int)buflen)
180
return;
181
buflen -= written;
182
183
if (grp->gr_mem != NULL) {
184
if (*(grp->gr_mem) != NULL) {
185
for (cp = grp->gr_mem; *cp; ++cp) {
186
written = snprintf(buffer, buflen, "%s%s",
187
cp == grp->gr_mem ? "" : ",", *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
const char *sep;
208
int i;
209
210
printf("1 line read from snapshot:\n%s\n", line);
211
212
i = 0;
213
sl = NULL;
214
ps = line;
215
sep = ":";
216
memset(grp, 0, sizeof(struct group));
217
while ((s = strsep(&ps, sep)) != NULL) {
218
switch (i) {
219
case 0:
220
grp->gr_name = strdup(s);
221
ATF_REQUIRE(grp->gr_name != NULL);
222
break;
223
224
case 1:
225
grp->gr_passwd = strdup(s);
226
ATF_REQUIRE(grp->gr_passwd != NULL);
227
break;
228
229
case 2:
230
grp->gr_gid = (gid_t)strtol(s, &ts, 10);
231
if (*ts != '\0') {
232
free(grp->gr_name);
233
free(grp->gr_passwd);
234
grp->gr_name = NULL;
235
grp->gr_passwd = NULL;
236
return (-1);
237
}
238
/* Change to parsing groups. */
239
sep = ",";
240
break;
241
242
default:
243
if (sl == NULL) {
244
if (strcmp(s, "(null)") == 0)
245
return (0);
246
247
sl = sl_init();
248
ATF_REQUIRE(sl != NULL);
249
250
if (strcmp(s, "nomem") != 0) {
251
ts = strdup(s);
252
ATF_REQUIRE(ts != NULL);
253
sl_add(sl, ts);
254
}
255
} else {
256
ts = strdup(s);
257
ATF_REQUIRE(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
int (*cb)(struct group *, void *))
294
{
295
struct group *grp;
296
const int limit = 1024;
297
int count = 0;
298
299
setgroupent(1);
300
while ((grp = getgrent()) != NULL) {
301
if (group_test_correctness(grp, NULL) == 0) {
302
TEST_DATA_APPEND(group, td, grp);
303
if (cb != NULL && cb(grp, td) != 0)
304
return (-1);
305
} else {
306
return (-1);
307
}
308
if (++count >= limit)
309
break;
310
}
311
endgrent();
312
313
return (0);
314
}
315
316
static int
317
group_test_correctness(struct group *grp, void *mdata __unused)
318
{
319
printf("testing correctness with the following data:\n");
320
dump_group(grp);
321
322
if (grp == NULL)
323
goto errfin;
324
325
if (grp->gr_name == NULL)
326
goto errfin;
327
328
if (grp->gr_passwd == NULL)
329
goto errfin;
330
331
if (grp->gr_mem == NULL)
332
goto errfin;
333
334
printf("correct\n");
335
336
return (0);
337
errfin:
338
printf("incorrect\n");
339
340
return (-1);
341
}
342
343
/* group_check_ambiguity() is needed here because when doing the getgrent()
344
* calls sequence, records from different nsswitch sources can be different,
345
* though having the same pw_name/pw_uid */
346
static int
347
group_check_ambiguity(struct group_test_data *td, struct group *pwd)
348
{
349
350
return (TEST_DATA_FIND(group, td, pwd, compare_group, NULL) !=
351
NULL ? 0 : -1);
352
}
353
354
static int
355
group_test_getgrnam(struct group *grp_model, void *mdata)
356
{
357
struct group *grp;
358
359
printf("testing getgrnam() with the following data:\n");
360
dump_group(grp_model);
361
362
grp = getgrnam(grp_model->gr_name);
363
if (group_test_correctness(grp, NULL) != 0)
364
goto errfin;
365
366
if (compare_group(grp, grp_model, NULL) != 0 &&
367
group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)
368
goto errfin;
369
370
return (0);
371
372
errfin:
373
return (-1);
374
}
375
376
static int
377
group_test_getgrgid(struct group *grp_model, void *mdata)
378
{
379
struct group *grp;
380
381
printf("testing getgrgid() with the following data...\n");
382
dump_group(grp_model);
383
384
grp = getgrgid(grp_model->gr_gid);
385
if (group_test_correctness(grp, NULL) != 0 ||
386
(compare_group(grp, grp_model, NULL) != 0 &&
387
group_check_ambiguity((struct group_test_data *)mdata, grp) != 0))
388
return (-1);
389
else
390
return (0);
391
}
392
393
static int
394
group_test_getgrent(struct group *grp, void *mdata __unused)
395
{
396
/*
397
* Only correctness can be checked when doing 1-pass test for
398
* getgrent().
399
*/
400
return (group_test_correctness(grp, NULL));
401
}
402
403
static int
404
run_tests(const char *snapshot_file, enum test_methods method)
405
{
406
struct group_test_data td, td_snap, td_2pass, td_interleaved;
407
int rv;
408
409
TEST_DATA_INIT(group, &td, clone_group, free_group);
410
TEST_DATA_INIT(group, &td_snap, clone_group, free_group);
411
if (snapshot_file != NULL) {
412
if (access(snapshot_file, W_OK | R_OK) != 0) {
413
if (errno == ENOENT)
414
method = TEST_BUILD_SNAPSHOT;
415
else {
416
printf("can't access the file %s\n",
417
snapshot_file);
418
419
rv = -1;
420
goto fin;
421
}
422
} else {
423
if (method == TEST_BUILD_SNAPSHOT) {
424
rv = 0;
425
goto fin;
426
}
427
428
TEST_SNAPSHOT_FILE_READ(group, snapshot_file,
429
&td_snap, group_read_snapshot_func);
430
}
431
}
432
433
rv = group_fill_test_data(&td, NULL);
434
if (rv == -1)
435
return (-1);
436
switch (method) {
437
case TEST_GETGRNAM:
438
if (snapshot_file == NULL)
439
rv = DO_1PASS_TEST(group, &td,
440
group_test_getgrnam, (void *)&td);
441
else
442
rv = DO_1PASS_TEST(group, &td_snap,
443
group_test_getgrnam, (void *)&td_snap);
444
break;
445
case TEST_GETGRGID:
446
if (snapshot_file == NULL)
447
rv = DO_1PASS_TEST(group, &td,
448
group_test_getgrgid, (void *)&td);
449
else
450
rv = DO_1PASS_TEST(group, &td_snap,
451
group_test_getgrgid, (void *)&td_snap);
452
break;
453
case TEST_GETGRENT:
454
if (snapshot_file == NULL)
455
rv = DO_1PASS_TEST(group, &td, group_test_getgrent,
456
(void *)&td);
457
else
458
rv = DO_2PASS_TEST(group, &td, &td_snap,
459
compare_group, NULL);
460
break;
461
case TEST_GETGRENT_2PASS:
462
TEST_DATA_INIT(group, &td_2pass, clone_group, free_group);
463
rv = group_fill_test_data(&td_2pass, NULL);
464
if (rv != -1)
465
rv = DO_2PASS_TEST(group, &td, &td_2pass,
466
compare_group, NULL);
467
TEST_DATA_DESTROY(group, &td_2pass);
468
break;
469
case TEST_GETGRENT_INTERLEAVED_GETGRNAM:
470
TEST_DATA_INIT(group, &td_interleaved, clone_group, free_group);
471
rv = group_fill_test_data(&td_interleaved, group_test_getgrnam);
472
if (rv != -1)
473
rv = DO_2PASS_TEST(group, &td, &td_interleaved,
474
compare_group, NULL);
475
TEST_DATA_DESTROY(group, &td_interleaved);
476
break;
477
case TEST_GETGRENT_INTERLEAVED_GETGRGID:
478
TEST_DATA_INIT(group, &td_interleaved, clone_group, free_group);
479
rv = group_fill_test_data(&td_interleaved, group_test_getgrgid);
480
if (rv != -1)
481
rv = DO_2PASS_TEST(group, &td, &td_interleaved,
482
compare_group, NULL);
483
TEST_DATA_DESTROY(group, &td_interleaved);
484
break;
485
case TEST_BUILD_SNAPSHOT:
486
if (snapshot_file != NULL)
487
rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td,
488
sdump_group);
489
break;
490
default:
491
rv = 0;
492
break;
493
}
494
495
fin:
496
TEST_DATA_DESTROY(group, &td_snap);
497
TEST_DATA_DESTROY(group, &td);
498
499
return (rv);
500
}
501
502
#define SNAPSHOT_FILE "snapshot_grp"
503
504
ATF_TC_WITHOUT_HEAD(getgrent);
505
ATF_TC_BODY(getgrent, tc)
506
{
507
ATF_REQUIRE(run_tests(NULL, TEST_GETGRENT) == 0);
508
}
509
510
ATF_TC_WITHOUT_HEAD(getgrent_with_snapshot);
511
ATF_TC_BODY(getgrent_with_snapshot, tc)
512
{
513
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
514
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0);
515
}
516
517
ATF_TC_WITHOUT_HEAD(getgrent_with_two_pass);
518
ATF_TC_BODY(getgrent_with_two_pass, tc)
519
{
520
ATF_REQUIRE(run_tests(NULL, TEST_GETGRENT_2PASS) == 0);
521
}
522
523
ATF_TC_WITHOUT_HEAD(getgrgid);
524
ATF_TC_BODY(getgrgid, tc)
525
{
526
ATF_REQUIRE(run_tests(NULL, TEST_GETGRGID) == 0);
527
}
528
529
ATF_TC_WITHOUT_HEAD(getgrgid_with_snapshot);
530
ATF_TC_BODY(getgrgid_with_snapshot, tc)
531
{
532
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
533
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0);
534
}
535
536
ATF_TC_WITHOUT_HEAD(getgrnam);
537
ATF_TC_BODY(getgrnam, tc)
538
{
539
ATF_REQUIRE(run_tests(NULL, TEST_GETGRNAM) == 0);
540
}
541
542
ATF_TC_WITHOUT_HEAD(getgrnam_with_snapshot);
543
ATF_TC_BODY(getgrnam_with_snapshot, tc)
544
{
545
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
546
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0);
547
}
548
549
ATF_TC_WITHOUT_HEAD(getgrent_interleaved_getgrnam);
550
ATF_TC_BODY(getgrent_interleaved_getgrnam, tc)
551
{
552
ATF_REQUIRE(run_tests(NULL, TEST_GETGRENT_INTERLEAVED_GETGRNAM) == 0);
553
}
554
555
ATF_TC_WITHOUT_HEAD(getgrent_interleaved_getgrgid);
556
ATF_TC_BODY(getgrent_interleaved_getgrgid, tc)
557
{
558
ATF_REQUIRE(run_tests(NULL, TEST_GETGRENT_INTERLEAVED_GETGRGID) == 0);
559
}
560
561
ATF_TP_ADD_TCS(tp)
562
{
563
ATF_TP_ADD_TC(tp, getgrent);
564
ATF_TP_ADD_TC(tp, getgrent_with_snapshot);
565
ATF_TP_ADD_TC(tp, getgrent_with_two_pass);
566
ATF_TP_ADD_TC(tp, getgrgid);
567
ATF_TP_ADD_TC(tp, getgrgid_with_snapshot);
568
ATF_TP_ADD_TC(tp, getgrnam);
569
ATF_TP_ADD_TC(tp, getgrnam_with_snapshot);
570
ATF_TP_ADD_TC(tp, getgrent_interleaved_getgrnam);
571
ATF_TP_ADD_TC(tp, getgrent_interleaved_getgrgid);
572
573
return (atf_no_error());
574
}
575
576