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: stable/11/lib/libc/tests/nss/getpw_test.c 319299 2017-05-31 08:32:05Z ngie $"); 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 42enum test_methods { 43 TEST_GETPWENT, 44 TEST_GETPWNAM, 45 TEST_GETPWUID, 46 TEST_GETPWENT_2PASS, 47 TEST_BUILD_SNAPSHOT 48}; 49 50DECLARE_TEST_DATA(passwd) 51DECLARE_TEST_FILE_SNAPSHOT(passwd) 52DECLARE_1PASS_TEST(passwd) 53DECLARE_2PASS_TEST(passwd) 54 55static void clone_passwd(struct passwd *, struct passwd const *); 56static int compare_passwd(struct passwd *, struct passwd *, void *); 57static void free_passwd(struct passwd *); 58 59static void sdump_passwd(struct passwd *, char *, size_t); 60#ifdef DEBUG 61static void dump_passwd(struct passwd *); 62#endif 63 64static int passwd_read_snapshot_func(struct passwd *, char *); 65 66static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *); 67static int passwd_fill_test_data(struct passwd_test_data *); 68static int passwd_test_correctness(struct passwd *, void *); 69static int passwd_test_getpwnam(struct passwd *, void *); 70static int passwd_test_getpwuid(struct passwd *, void *); 71static int passwd_test_getpwent(struct passwd *, void *); 72 73IMPLEMENT_TEST_DATA(passwd) 74IMPLEMENT_TEST_FILE_SNAPSHOT(passwd) 75IMPLEMENT_1PASS_TEST(passwd) 76IMPLEMENT_2PASS_TEST(passwd) 77 78static void 79clone_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 99static int 100compare_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 124static void 125free_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 135static void 136sdump_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 146static void 147dump_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 158static int 159passwd_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 228fin: 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 238static int 239passwd_fill_test_data(struct passwd_test_data *td) 240{ 241 struct passwd *pwd; 242 243 setpassent(1); 244 while ((pwd = getpwent()) != NULL) { 245 if (passwd_test_correctness(pwd, NULL) == 0) 246 TEST_DATA_APPEND(passwd, td, pwd); 247 else 248 return (-1); 249 } 250 endpwent(); 251 252 return (0); 253} 254 255static int 256passwd_test_correctness(struct passwd *pwd, void *mdata __unused) 257{ 258 259#ifdef DEBUG 260 printf("testing correctness with the following data:\n"); 261 dump_passwd(pwd); 262#endif 263 264 if (pwd == NULL) 265 return (-1); 266 267 if (pwd->pw_name == NULL) 268 goto errfin; 269 270 if (pwd->pw_passwd == NULL) 271 goto errfin; 272 273 if (pwd->pw_class == NULL) 274 goto errfin; 275 276 if (pwd->pw_gecos == NULL) 277 goto errfin; 278 279 if (pwd->pw_dir == NULL) 280 goto errfin; 281 282 if (pwd->pw_shell == NULL) 283 goto errfin; 284 285#ifdef DEBUG 286 printf("correct\n"); 287#endif 288 289 return (0); 290errfin: 291#ifdef DEBUG 292 printf("incorrect\n"); 293#endif 294 295 return (-1); 296} 297 298/* passwd_check_ambiguity() is needed here because when doing the getpwent() 299 * calls sequence, records from different nsswitch sources can be different, 300 * though having the same pw_name/pw_uid */ 301static int 302passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd) 303{ 304 305 return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd, 306 NULL) != NULL ? 0 : -1); 307} 308 309static int 310passwd_test_getpwnam(struct passwd *pwd_model, void *mdata) 311{ 312 struct passwd *pwd; 313 314#ifdef DEBUG 315 printf("testing getpwnam() with the following data:\n"); 316 dump_passwd(pwd_model); 317#endif 318 319 pwd = getpwnam(pwd_model->pw_name); 320 if (passwd_test_correctness(pwd, NULL) != 0) 321 goto errfin; 322 323 if ((compare_passwd(pwd, pwd_model, NULL) != 0) && 324 (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) 325 !=0)) 326 goto errfin; 327 328#ifdef DEBUG 329 printf("ok\n"); 330#endif 331 return (0); 332 333errfin: 334#ifdef DEBUG 335 printf("not ok\n"); 336#endif 337 return (-1); 338} 339 340static int 341passwd_test_getpwuid(struct passwd *pwd_model, void *mdata) 342{ 343 struct passwd *pwd; 344 345#ifdef DEBUG 346 printf("testing getpwuid() with the following data...\n"); 347 dump_passwd(pwd_model); 348#endif 349 350 pwd = getpwuid(pwd_model->pw_uid); 351 if ((passwd_test_correctness(pwd, NULL) != 0) || 352 ((compare_passwd(pwd, pwd_model, NULL) != 0) && 353 (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) 354 != 0))) { 355#ifdef DEBUG 356 printf("not ok\n"); 357#endif 358 return (-1); 359 } else { 360#ifdef DEBUG 361 printf("ok\n"); 362#endif 363 return (0); 364 } 365} 366 367static int 368passwd_test_getpwent(struct passwd *pwd, void *mdata __unused) 369{ 370 /* Only correctness can be checked when doing 1-pass test for 371 * getpwent(). */ 372 return (passwd_test_correctness(pwd, NULL)); 373} 374 375static int 376run_tests(const char *snapshot_file, enum test_methods method) 377{ 378 struct passwd_test_data td, td_snap, td_2pass; 379 int rv; 380 381 TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd); 382 TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd); 383 if (snapshot_file != NULL) { 384 if (access(snapshot_file, W_OK | R_OK) != 0) { 385 if (errno == ENOENT) 386 method = TEST_BUILD_SNAPSHOT; 387 else { 388 printf("can't access the file %s\n", 389 snapshot_file); 390 rv = -1; 391 goto fin; 392 } 393 } else { 394 if (method == TEST_BUILD_SNAPSHOT) { 395 rv = 0; 396 goto fin; 397 } 398 399 TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file, 400 &td_snap, passwd_read_snapshot_func); 401 } 402 } 403 404 rv = passwd_fill_test_data(&td); 405 if (rv == -1) 406 return (-1); 407 408 switch (method) { 409 case TEST_GETPWNAM: 410 if (snapshot_file == NULL) 411 rv = DO_1PASS_TEST(passwd, &td, 412 passwd_test_getpwnam, (void *)&td); 413 else 414 rv = DO_1PASS_TEST(passwd, &td_snap, 415 passwd_test_getpwnam, (void *)&td_snap); 416 break; 417 case TEST_GETPWUID: 418 if (snapshot_file == NULL) 419 rv = DO_1PASS_TEST(passwd, &td, 420 passwd_test_getpwuid, (void *)&td); 421 else 422 rv = DO_1PASS_TEST(passwd, &td_snap, 423 passwd_test_getpwuid, (void *)&td_snap); 424 break; 425 case TEST_GETPWENT: 426 if (snapshot_file == NULL) 427 rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent, 428 (void *)&td); 429 else 430 rv = DO_2PASS_TEST(passwd, &td, &td_snap, 431 compare_passwd, NULL); 432 break; 433 case TEST_GETPWENT_2PASS: 434 TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd); 435 rv = passwd_fill_test_data(&td_2pass); 436 if (rv != -1) 437 rv = DO_2PASS_TEST(passwd, &td, &td_2pass, 438 compare_passwd, NULL); 439 TEST_DATA_DESTROY(passwd, &td_2pass); 440 break; 441 case TEST_BUILD_SNAPSHOT: 442 if (snapshot_file != NULL) 443 rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file, 444 &td, sdump_passwd); 445 break; 446 default: 447 rv = 0; 448 break; 449 } 450 451fin: 452 TEST_DATA_DESTROY(passwd, &td_snap); 453 TEST_DATA_DESTROY(passwd, &td); 454 455 return (rv); 456} 457 458#define SNAPSHOT_FILE "snapshot_pwd" 459 460ATF_TC_WITHOUT_HEAD(build_snapshot); 461ATF_TC_BODY(build_snapshot, tc) 462{ 463 464 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 465} 466 467ATF_TC_WITHOUT_HEAD(getpwent); 468ATF_TC_BODY(getpwent, tc) 469{ 470 471 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0); 472} 473 474ATF_TC_WITHOUT_HEAD(getpwent_with_snapshot); 475ATF_TC_BODY(getpwent_with_snapshot, tc) 476{ 477 478 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 479 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0); 480} 481 482ATF_TC_WITHOUT_HEAD(getpwent_with_two_pass); 483ATF_TC_BODY(getpwent_with_two_pass, tc) 484{ 485 486 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT_2PASS) == 0); 487} 488 489ATF_TC_WITHOUT_HEAD(getpwnam); 490ATF_TC_BODY(getpwnam, tc) 491{ 492 493 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0); 494} 495 496ATF_TC_WITHOUT_HEAD(getpwnam_with_snapshot); 497ATF_TC_BODY(getpwnam_with_snapshot, tc) 498{ 499 500 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 501 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0); 502} 503 504ATF_TC_WITHOUT_HEAD(getpwuid); 505ATF_TC_BODY(getpwuid, tc) 506{ 507 508 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0); 509} 510 511ATF_TC_WITHOUT_HEAD(getpwuid_with_snapshot); 512ATF_TC_BODY(getpwuid_with_snapshot, tc) 513{ 514 515 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 516 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0); 517} 518 519ATF_TP_ADD_TCS(tp) 520{ 521 522 ATF_TP_ADD_TC(tp, build_snapshot); 523 ATF_TP_ADD_TC(tp, getpwent); 524 ATF_TP_ADD_TC(tp, getpwent_with_snapshot); 525 ATF_TP_ADD_TC(tp, getpwent_with_two_pass); 526 ATF_TP_ADD_TC(tp, getpwnam); 527 ATF_TP_ADD_TC(tp, getpwnam_with_snapshot); 528 ATF_TP_ADD_TC(tp, getpwuid); 529 ATF_TP_ADD_TC(tp, getpwuid_with_snapshot); 530 531 return (atf_no_error()); 532} 533