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