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