Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/nss/getpw_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 <errno.h>
29
#include <pwd.h>
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#include <unistd.h>
34
35
#include <atf-c.h>
36
37
#include "testutil.h"
38
39
enum test_methods {
40
TEST_GETPWENT,
41
TEST_GETPWENT_INTERLEAVED_GETPWNAM,
42
TEST_GETPWENT_INTERLEAVED_GETPWUID,
43
TEST_GETPWNAM,
44
TEST_GETPWUID,
45
TEST_GETPWENT_2PASS,
46
TEST_BUILD_SNAPSHOT
47
};
48
49
DECLARE_TEST_DATA(passwd)
50
DECLARE_TEST_FILE_SNAPSHOT(passwd)
51
DECLARE_1PASS_TEST(passwd)
52
DECLARE_2PASS_TEST(passwd)
53
54
static void clone_passwd(struct passwd *, struct passwd const *);
55
static int compare_passwd(struct passwd *, struct passwd *, void *);
56
static void free_passwd(struct passwd *);
57
58
static void sdump_passwd(struct passwd *, char *, size_t);
59
#ifdef DEBUG
60
static void dump_passwd(struct passwd *);
61
#endif
62
63
static int passwd_read_snapshot_func(struct passwd *, char *);
64
65
static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *);
66
static int passwd_fill_test_data(struct passwd_test_data *,
67
int (*cb)(struct passwd *, void *));
68
static int passwd_test_correctness(struct passwd *, void *);
69
static int passwd_test_getpwnam(struct passwd *, void *);
70
static int passwd_test_getpwuid(struct passwd *, void *);
71
static int passwd_test_getpwent(struct passwd *, void *);
72
73
IMPLEMENT_TEST_DATA(passwd)
74
IMPLEMENT_TEST_FILE_SNAPSHOT(passwd)
75
IMPLEMENT_1PASS_TEST(passwd)
76
IMPLEMENT_2PASS_TEST(passwd)
77
78
static void
79
clone_passwd(struct passwd *dest, struct passwd const *src)
80
{
81
ATF_REQUIRE(dest != NULL);
82
ATF_REQUIRE(src != NULL);
83
84
memcpy(dest, src, sizeof(struct passwd));
85
if (src->pw_name != NULL)
86
dest->pw_name = strdup(src->pw_name);
87
if (src->pw_passwd != NULL)
88
dest->pw_passwd = strdup(src->pw_passwd);
89
if (src->pw_class != NULL)
90
dest->pw_class = strdup(src->pw_class);
91
if (src->pw_gecos != NULL)
92
dest->pw_gecos = strdup(src->pw_gecos);
93
if (src->pw_dir != NULL)
94
dest->pw_dir = strdup(src->pw_dir);
95
if (src->pw_shell != NULL)
96
dest->pw_shell = strdup(dest->pw_shell);
97
}
98
99
static int
100
compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata __unused)
101
{
102
ATF_REQUIRE(pwd1 != NULL);
103
ATF_REQUIRE(pwd2 != NULL);
104
105
if (pwd1 == pwd2)
106
return (0);
107
108
if (pwd1->pw_uid != pwd2->pw_uid ||
109
pwd1->pw_gid != pwd2->pw_gid ||
110
pwd1->pw_change != pwd2->pw_change ||
111
pwd1->pw_expire != pwd2->pw_expire ||
112
pwd1->pw_fields != pwd2->pw_fields ||
113
strcmp(pwd1->pw_name, pwd2->pw_name) != 0 ||
114
strcmp(pwd1->pw_passwd, pwd2->pw_passwd) != 0 ||
115
strcmp(pwd1->pw_class, pwd2->pw_class) != 0 ||
116
strcmp(pwd1->pw_gecos, pwd2->pw_gecos) != 0 ||
117
strcmp(pwd1->pw_dir, pwd2->pw_dir) != 0 ||
118
strcmp(pwd1->pw_shell, pwd2->pw_shell) != 0)
119
return (-1);
120
else
121
return (0);
122
}
123
124
static void
125
free_passwd(struct passwd *pwd)
126
{
127
free(pwd->pw_name);
128
free(pwd->pw_passwd);
129
free(pwd->pw_class);
130
free(pwd->pw_gecos);
131
free(pwd->pw_dir);
132
free(pwd->pw_shell);
133
}
134
135
static void
136
sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen)
137
{
138
snprintf(buffer, buflen, "%s:%s:%d:%d:%jd:%s:%s:%s:%s:%jd:%d",
139
pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
140
(uintmax_t)pwd->pw_change, pwd->pw_class, pwd->pw_gecos,
141
pwd->pw_dir, pwd->pw_shell, (uintmax_t)pwd->pw_expire,
142
pwd->pw_fields);
143
}
144
145
#ifdef DEBUG
146
static void
147
dump_passwd(struct passwd *pwd)
148
{
149
if (pwd != NULL) {
150
char buffer[2048];
151
sdump_passwd(pwd, buffer, sizeof(buffer));
152
printf("%s\n", buffer);
153
} else
154
printf("(null)\n");
155
}
156
#endif
157
158
static int
159
passwd_read_snapshot_func(struct passwd *pwd, char *line)
160
{
161
char *s, *ps, *ts;
162
int i;
163
164
#ifdef DEBUG
165
printf("1 line read from snapshot:\n%s\n", line);
166
#endif
167
168
i = 0;
169
ps = line;
170
memset(pwd, 0, sizeof(struct passwd));
171
while ((s = strsep(&ps, ":")) != NULL) {
172
switch (i) {
173
case 0:
174
pwd->pw_name = strdup(s);
175
ATF_REQUIRE(pwd->pw_name != NULL);
176
break;
177
case 1:
178
pwd->pw_passwd = strdup(s);
179
ATF_REQUIRE(pwd->pw_passwd != NULL);
180
break;
181
case 2:
182
pwd->pw_uid = (uid_t)strtol(s, &ts, 10);
183
if (*ts != '\0')
184
goto fin;
185
break;
186
case 3:
187
pwd->pw_gid = (gid_t)strtol(s, &ts, 10);
188
if (*ts != '\0')
189
goto fin;
190
break;
191
case 4:
192
pwd->pw_change = (time_t)strtol(s, &ts, 10);
193
if (*ts != '\0')
194
goto fin;
195
break;
196
case 5:
197
pwd->pw_class = strdup(s);
198
ATF_REQUIRE(pwd->pw_class != NULL);
199
break;
200
case 6:
201
pwd->pw_gecos = strdup(s);
202
ATF_REQUIRE(pwd->pw_gecos != NULL);
203
break;
204
case 7:
205
pwd->pw_dir = strdup(s);
206
ATF_REQUIRE(pwd->pw_dir != NULL);
207
break;
208
case 8:
209
pwd->pw_shell = strdup(s);
210
ATF_REQUIRE(pwd->pw_shell != NULL);
211
break;
212
case 9:
213
pwd->pw_expire = (time_t)strtol(s, &ts, 10);
214
if (*ts != '\0')
215
goto fin;
216
break;
217
case 10:
218
pwd->pw_fields = (int)strtol(s, &ts, 10);
219
if (*ts != '\0')
220
goto fin;
221
break;
222
default:
223
break;
224
}
225
++i;
226
}
227
228
fin:
229
if (i != 11) {
230
free_passwd(pwd);
231
memset(pwd, 0, sizeof(struct passwd));
232
return (-1);
233
}
234
235
return (0);
236
}
237
238
static int
239
passwd_fill_test_data(struct passwd_test_data *td,
240
int (*cb)(struct passwd *, void *))
241
{
242
struct passwd *pwd;
243
const int limit = 1024;
244
int count = 0;
245
246
setpassent(1);
247
while ((pwd = getpwent()) != NULL) {
248
if (passwd_test_correctness(pwd, NULL) == 0) {
249
TEST_DATA_APPEND(passwd, td, pwd);
250
if (cb != NULL && cb(pwd, td) != 0)
251
return (-1);
252
} else {
253
return (-1);
254
}
255
if (++count >= limit)
256
break;
257
}
258
endpwent();
259
260
return (0);
261
}
262
263
static int
264
passwd_test_correctness(struct passwd *pwd, void *mdata __unused)
265
{
266
267
#ifdef DEBUG
268
printf("testing correctness with the following data:\n");
269
dump_passwd(pwd);
270
#endif
271
272
if (pwd == NULL)
273
return (-1);
274
275
if (pwd->pw_name == NULL)
276
goto errfin;
277
278
if (pwd->pw_passwd == NULL)
279
goto errfin;
280
281
if (pwd->pw_class == NULL)
282
goto errfin;
283
284
if (pwd->pw_gecos == NULL)
285
goto errfin;
286
287
if (pwd->pw_dir == NULL)
288
goto errfin;
289
290
if (pwd->pw_shell == NULL)
291
goto errfin;
292
293
#ifdef DEBUG
294
printf("correct\n");
295
#endif
296
297
return (0);
298
errfin:
299
#ifdef DEBUG
300
printf("incorrect\n");
301
#endif
302
303
return (-1);
304
}
305
306
/* passwd_check_ambiguity() is needed here because when doing the getpwent()
307
* calls sequence, records from different nsswitch sources can be different,
308
* though having the same pw_name/pw_uid */
309
static int
310
passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd)
311
{
312
313
return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd, NULL) !=
314
NULL ? 0 : -1);
315
}
316
317
static int
318
passwd_test_getpwnam(struct passwd *pwd_model, void *mdata)
319
{
320
struct passwd *pwd;
321
322
#ifdef DEBUG
323
printf("testing getpwnam() with the following data:\n");
324
dump_passwd(pwd_model);
325
#endif
326
327
pwd = getpwnam(pwd_model->pw_name);
328
if (passwd_test_correctness(pwd, NULL) != 0)
329
goto errfin;
330
331
if (compare_passwd(pwd, pwd_model, NULL) != 0 &&
332
passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) != 0)
333
goto errfin;
334
335
#ifdef DEBUG
336
printf("ok\n");
337
#endif
338
return (0);
339
340
errfin:
341
#ifdef DEBUG
342
printf("not ok\n");
343
#endif
344
return (-1);
345
}
346
347
static int
348
passwd_test_getpwuid(struct passwd *pwd_model, void *mdata)
349
{
350
struct passwd *pwd;
351
352
#ifdef DEBUG
353
printf("testing getpwuid() with the following data...\n");
354
dump_passwd(pwd_model);
355
#endif
356
357
pwd = getpwuid(pwd_model->pw_uid);
358
if (passwd_test_correctness(pwd, NULL) != 0 ||
359
(compare_passwd(pwd, pwd_model, NULL) != 0 &&
360
passwd_check_ambiguity((struct passwd_test_data *)mdata,
361
pwd) != 0)) {
362
#ifdef DEBUG
363
printf("not ok\n");
364
#endif
365
return (-1);
366
} else {
367
#ifdef DEBUG
368
printf("ok\n");
369
#endif
370
return (0);
371
}
372
}
373
374
static int
375
passwd_test_getpwent(struct passwd *pwd, void *mdata __unused)
376
{
377
/*
378
* Only correctness can be checked when doing 1-pass test for
379
* getpwent().
380
*/
381
return (passwd_test_correctness(pwd, NULL));
382
}
383
384
static int
385
run_tests(const char *snapshot_file, enum test_methods method)
386
{
387
struct passwd_test_data td, td_snap, td_2pass, td_interleaved;
388
int rv;
389
390
TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd);
391
TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd);
392
if (snapshot_file != NULL) {
393
if (access(snapshot_file, W_OK | R_OK) != 0) {
394
if (errno == ENOENT)
395
method = TEST_BUILD_SNAPSHOT;
396
else {
397
printf("can't access the file %s\n",
398
snapshot_file);
399
rv = -1;
400
goto fin;
401
}
402
} else {
403
if (method == TEST_BUILD_SNAPSHOT) {
404
rv = 0;
405
goto fin;
406
}
407
408
TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file,
409
&td_snap, passwd_read_snapshot_func);
410
}
411
}
412
413
rv = passwd_fill_test_data(&td, NULL);
414
if (rv == -1)
415
return (-1);
416
417
switch (method) {
418
case TEST_GETPWNAM:
419
if (snapshot_file == NULL)
420
rv = DO_1PASS_TEST(passwd, &td,
421
passwd_test_getpwnam, (void *)&td);
422
else
423
rv = DO_1PASS_TEST(passwd, &td_snap,
424
passwd_test_getpwnam, (void *)&td_snap);
425
break;
426
case TEST_GETPWUID:
427
if (snapshot_file == NULL)
428
rv = DO_1PASS_TEST(passwd, &td,
429
passwd_test_getpwuid, (void *)&td);
430
else
431
rv = DO_1PASS_TEST(passwd, &td_snap,
432
passwd_test_getpwuid, (void *)&td_snap);
433
break;
434
case TEST_GETPWENT:
435
if (snapshot_file == NULL)
436
rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent,
437
(void *)&td);
438
else
439
rv = DO_2PASS_TEST(passwd, &td, &td_snap,
440
compare_passwd, NULL);
441
break;
442
case TEST_GETPWENT_2PASS:
443
TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd);
444
rv = passwd_fill_test_data(&td_2pass, NULL);
445
if (rv != -1)
446
rv = DO_2PASS_TEST(passwd, &td, &td_2pass,
447
compare_passwd, NULL);
448
TEST_DATA_DESTROY(passwd, &td_2pass);
449
break;
450
case TEST_GETPWENT_INTERLEAVED_GETPWNAM:
451
TEST_DATA_INIT(passwd, &td_interleaved, clone_passwd, free_passwd);
452
rv = passwd_fill_test_data(&td_interleaved, passwd_test_getpwnam);
453
if (rv != -1)
454
rv = DO_2PASS_TEST(passwd, &td, &td_interleaved,
455
compare_passwd, NULL);
456
TEST_DATA_DESTROY(passwd, &td_interleaved);
457
break;
458
case TEST_GETPWENT_INTERLEAVED_GETPWUID:
459
TEST_DATA_INIT(passwd, &td_interleaved, clone_passwd, free_passwd);
460
rv = passwd_fill_test_data(&td_interleaved, passwd_test_getpwuid);
461
if (rv != -1)
462
rv = DO_2PASS_TEST(passwd, &td, &td_interleaved,
463
compare_passwd, NULL);
464
TEST_DATA_DESTROY(passwd, &td_interleaved);
465
break;
466
case TEST_BUILD_SNAPSHOT:
467
if (snapshot_file != NULL)
468
rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file,
469
&td, sdump_passwd);
470
break;
471
default:
472
rv = 0;
473
break;
474
}
475
476
fin:
477
TEST_DATA_DESTROY(passwd, &td_snap);
478
TEST_DATA_DESTROY(passwd, &td);
479
480
return (rv);
481
}
482
483
#define SNAPSHOT_FILE "snapshot_pwd"
484
485
ATF_TC_WITHOUT_HEAD(getpwent);
486
ATF_TC_BODY(getpwent, tc)
487
{
488
ATF_REQUIRE(run_tests(NULL, TEST_GETPWENT) == 0);
489
}
490
491
ATF_TC_WITHOUT_HEAD(getpwent_with_snapshot);
492
ATF_TC_BODY(getpwent_with_snapshot, tc)
493
{
494
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
495
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0);
496
}
497
498
ATF_TC_WITHOUT_HEAD(getpwent_with_two_pass);
499
ATF_TC_BODY(getpwent_with_two_pass, tc)
500
{
501
ATF_REQUIRE(run_tests(NULL, TEST_GETPWENT_2PASS) == 0);
502
}
503
504
ATF_TC_WITHOUT_HEAD(getpwnam);
505
ATF_TC_BODY(getpwnam, tc)
506
{
507
ATF_REQUIRE(run_tests(NULL, TEST_GETPWNAM) == 0);
508
}
509
510
ATF_TC_WITHOUT_HEAD(getpwnam_with_snapshot);
511
ATF_TC_BODY(getpwnam_with_snapshot, tc)
512
{
513
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
514
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0);
515
}
516
517
ATF_TC_WITHOUT_HEAD(getpwuid);
518
ATF_TC_BODY(getpwuid, tc)
519
{
520
ATF_REQUIRE(run_tests(NULL, TEST_GETPWUID) == 0);
521
}
522
523
ATF_TC_WITHOUT_HEAD(getpwuid_with_snapshot);
524
ATF_TC_BODY(getpwuid_with_snapshot, tc)
525
{
526
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
527
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0);
528
}
529
530
ATF_TC_WITHOUT_HEAD(getpwent_interleaved_getpwnam);
531
ATF_TC_BODY(getpwent_interleaved_getpwnam, tc)
532
{
533
ATF_REQUIRE(run_tests(NULL, TEST_GETPWENT_INTERLEAVED_GETPWNAM) == 0);
534
}
535
536
ATF_TC_WITHOUT_HEAD(getpwent_interleaved_getpwuid);
537
ATF_TC_BODY(getpwent_interleaved_getpwuid, tc)
538
{
539
ATF_REQUIRE(run_tests(NULL, TEST_GETPWENT_INTERLEAVED_GETPWUID) == 0);
540
}
541
542
ATF_TP_ADD_TCS(tp)
543
{
544
ATF_TP_ADD_TC(tp, getpwent);
545
ATF_TP_ADD_TC(tp, getpwent_with_snapshot);
546
ATF_TP_ADD_TC(tp, getpwent_with_two_pass);
547
ATF_TP_ADD_TC(tp, getpwnam);
548
ATF_TP_ADD_TC(tp, getpwnam_with_snapshot);
549
ATF_TP_ADD_TC(tp, getpwuid);
550
ATF_TP_ADD_TC(tp, getpwuid_with_snapshot);
551
ATF_TP_ADD_TC(tp, getpwent_interleaved_getpwnam);
552
ATF_TP_ADD_TC(tp, getpwent_interleaved_getpwuid);
553
554
return (atf_no_error());
555
}
556
557