test-getpw.c revision 291759
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/10/tools/regression/lib/libc/nss/test-getpw.c 291759 2015-12-04 09:18:12Z ngie $"); 30 31#include <assert.h> 32#include <errno.h> 33#include <pwd.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <unistd.h> 38#include "testutil.h" 39 40enum test_methods { 41 TEST_GETPWENT, 42 TEST_GETPWNAM, 43 TEST_GETPWUID, 44 TEST_GETPWENT_2PASS, 45 TEST_BUILD_SNAPSHOT 46}; 47 48static int debug = 0; 49static enum test_methods method = TEST_BUILD_SNAPSHOT; 50 51DECLARE_TEST_DATA(passwd) 52DECLARE_TEST_FILE_SNAPSHOT(passwd) 53DECLARE_1PASS_TEST(passwd) 54DECLARE_2PASS_TEST(passwd) 55 56static void clone_passwd(struct passwd *, struct passwd const *); 57static int compare_passwd(struct passwd *, struct passwd *, void *); 58static void free_passwd(struct passwd *); 59 60static void sdump_passwd(struct passwd *, char *, size_t); 61static void dump_passwd(struct passwd *); 62 63static int passwd_read_snapshot_func(struct passwd *, char *); 64 65static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *); 66static int passwd_fill_test_data(struct passwd_test_data *); 67static int passwd_test_correctness(struct passwd *, void *); 68static int passwd_test_getpwnam(struct passwd *, void *); 69static int passwd_test_getpwuid(struct passwd *, void *); 70static int passwd_test_getpwent(struct passwd *, void *); 71 72static void usage(void) __attribute__((__noreturn__)); 73 74IMPLEMENT_TEST_DATA(passwd) 75IMPLEMENT_TEST_FILE_SNAPSHOT(passwd) 76IMPLEMENT_1PASS_TEST(passwd) 77IMPLEMENT_2PASS_TEST(passwd) 78 79static void 80clone_passwd(struct passwd *dest, struct passwd const *src) 81{ 82 assert(dest != NULL); 83 assert(src != NULL); 84 85 memcpy(dest, src, sizeof(struct passwd)); 86 if (src->pw_name != NULL) 87 dest->pw_name = strdup(src->pw_name); 88 if (src->pw_passwd != NULL) 89 dest->pw_passwd = strdup(src->pw_passwd); 90 if (src->pw_class != NULL) 91 dest->pw_class = strdup(src->pw_class); 92 if (src->pw_gecos != NULL) 93 dest->pw_gecos = strdup(src->pw_gecos); 94 if (src->pw_dir != NULL) 95 dest->pw_dir = strdup(src->pw_dir); 96 if (src->pw_shell != NULL) 97 dest->pw_shell = strdup(dest->pw_shell); 98} 99 100static int 101compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata) 102{ 103 assert(pwd1 != NULL); 104 assert(pwd2 != NULL); 105 106 if (pwd1 == pwd2) 107 return (0); 108 109 if ((pwd1->pw_uid != pwd2->pw_uid) || 110 (pwd1->pw_gid != pwd2->pw_gid) || 111 (pwd1->pw_change != pwd2->pw_change) || 112 (pwd1->pw_expire != pwd2->pw_expire) || 113 (pwd1->pw_fields != pwd2->pw_fields) || 114 (strcmp(pwd1->pw_name, pwd2->pw_name) != 0) || 115 (strcmp(pwd1->pw_passwd, pwd2->pw_passwd) != 0) || 116 (strcmp(pwd1->pw_class, pwd2->pw_class) != 0) || 117 (strcmp(pwd1->pw_gecos, pwd2->pw_gecos) != 0) || 118 (strcmp(pwd1->pw_dir, pwd2->pw_dir) != 0) || 119 (strcmp(pwd1->pw_shell, pwd2->pw_shell) != 0) 120 ) 121 return (-1); 122 else 123 return (0); 124} 125 126static void 127free_passwd(struct passwd *pwd) 128{ 129 free(pwd->pw_name); 130 free(pwd->pw_passwd); 131 free(pwd->pw_class); 132 free(pwd->pw_gecos); 133 free(pwd->pw_dir); 134 free(pwd->pw_shell); 135} 136 137static void 138sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen) 139{ 140 snprintf(buffer, buflen, "%s:%s:%d:%d:%d:%s:%s:%s:%s:%d:%d", 141 pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid, 142 pwd->pw_change, pwd->pw_class, pwd->pw_gecos, pwd->pw_dir, 143 pwd->pw_shell, pwd->pw_expire, pwd->pw_fields); 144} 145 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 157static int 158passwd_read_snapshot_func(struct passwd *pwd, char *line) 159{ 160 char *s, *ps, *ts; 161 int i; 162 163 if (debug) 164 printf("1 line read from snapshot:\n%s\n", line); 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 assert(pwd->pw_name != NULL); 174 break; 175 case 1: 176 pwd->pw_passwd = strdup(s); 177 assert(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 assert(pwd->pw_class != NULL); 197 break; 198 case 6: 199 pwd->pw_gecos = strdup(s); 200 assert(pwd->pw_gecos != NULL); 201 break; 202 case 7: 203 pwd->pw_dir = strdup(s); 204 assert(pwd->pw_dir != NULL); 205 break; 206 case 8: 207 pwd->pw_shell = strdup(s); 208 assert(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 226fin: 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 236static int 237passwd_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 253static int 254passwd_test_correctness(struct passwd *pwd, void *mdata) 255{ 256 if (debug) { 257 printf("testing correctness with the following data:\n"); 258 dump_passwd(pwd); 259 } 260 261 if (pwd == NULL) 262 return (-1); 263 264 if (pwd->pw_name == NULL) 265 goto errfin; 266 267 if (pwd->pw_passwd == NULL) 268 goto errfin; 269 270 if (pwd->pw_class == NULL) 271 goto errfin; 272 273 if (pwd->pw_gecos == NULL) 274 goto errfin; 275 276 if (pwd->pw_dir == NULL) 277 goto errfin; 278 279 if (pwd->pw_shell == NULL) 280 goto errfin; 281 282 if (debug) 283 printf("correct\n"); 284 285 return (0); 286errfin: 287 if (debug) 288 printf("incorrect\n"); 289 290 return (-1); 291} 292 293/* passwd_check_ambiguity() is needed here because when doing the getpwent() 294 * calls sequence, records from different nsswitch sources can be different, 295 * though having the same pw_name/pw_uid */ 296static int 297passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd) 298{ 299 300 return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd, 301 NULL) != NULL ? 0 : -1); 302} 303 304static int 305passwd_test_getpwnam(struct passwd *pwd_model, void *mdata) 306{ 307 struct passwd *pwd; 308 309 if (debug) { 310 printf("testing getpwnam() with the following data:\n"); 311 dump_passwd(pwd_model); 312 } 313 314 pwd = getpwnam(pwd_model->pw_name); 315 if (passwd_test_correctness(pwd, NULL) != 0) 316 goto errfin; 317 318 if ((compare_passwd(pwd, pwd_model, NULL) != 0) && 319 (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) 320 !=0)) 321 goto errfin; 322 323 if (debug) 324 printf("ok\n"); 325 return (0); 326 327errfin: 328 if (debug) 329 printf("not ok\n"); 330 331 return (-1); 332} 333 334static int 335passwd_test_getpwuid(struct passwd *pwd_model, void *mdata) 336{ 337 struct passwd *pwd; 338 339 if (debug) { 340 printf("testing getpwuid() with the following data...\n"); 341 dump_passwd(pwd_model); 342 } 343 344 pwd = getpwuid(pwd_model->pw_uid); 345 if ((passwd_test_correctness(pwd, NULL) != 0) || 346 ((compare_passwd(pwd, pwd_model, NULL) != 0) && 347 (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) 348 != 0))) { 349 if (debug) 350 printf("not ok\n"); 351 return (-1); 352 } else { 353 if (debug) 354 printf("ok\n"); 355 return (0); 356 } 357} 358 359static int 360passwd_test_getpwent(struct passwd *pwd, void *mdata) 361{ 362 /* Only correctness can be checked when doing 1-pass test for 363 * getpwent(). */ 364 return (passwd_test_correctness(pwd, NULL)); 365} 366 367static void 368usage(void) 369{ 370 (void)fprintf(stderr, 371 "Usage: %s -nue2 [-d] [-s <file>]\n", 372 getprogname()); 373 exit(1); 374} 375 376int 377main(int argc, char **argv) 378{ 379 struct passwd_test_data td, td_snap, td_2pass; 380 char *snapshot_file; 381 int rv; 382 int c; 383 384 if (argc < 2) 385 usage(); 386 387 snapshot_file = NULL; 388 while ((c = getopt(argc, argv, "nue2ds:")) != -1) 389 switch (c) { 390 case 'd': 391 debug++; 392 break; 393 case 'n': 394 method = TEST_GETPWNAM; 395 break; 396 case 'u': 397 method = TEST_GETPWUID; 398 break; 399 case 'e': 400 method = TEST_GETPWENT; 401 break; 402 case '2': 403 method = TEST_GETPWENT_2PASS; 404 break; 405 case 's': 406 snapshot_file = strdup(optarg); 407 break; 408 default: 409 usage(); 410 } 411 412 TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd); 413 TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd); 414 if (snapshot_file != NULL) { 415 if (access(snapshot_file, W_OK | R_OK) != 0) { 416 if (errno == ENOENT) 417 method = TEST_BUILD_SNAPSHOT; 418 else { 419 if (debug) 420 printf("can't access the file %s\n", 421 snapshot_file); 422 423 rv = -1; 424 goto fin; 425 } 426 } else { 427 if (method == TEST_BUILD_SNAPSHOT) { 428 rv = 0; 429 goto fin; 430 } 431 432 TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file, 433 &td_snap, passwd_read_snapshot_func); 434 } 435 } 436 437 rv = passwd_fill_test_data(&td); 438 if (rv == -1) 439 return (-1); 440 441 switch (method) { 442 case TEST_GETPWNAM: 443 if (snapshot_file == NULL) 444 rv = DO_1PASS_TEST(passwd, &td, 445 passwd_test_getpwnam, (void *)&td); 446 else 447 rv = DO_1PASS_TEST(passwd, &td_snap, 448 passwd_test_getpwnam, (void *)&td_snap); 449 break; 450 case TEST_GETPWUID: 451 if (snapshot_file == NULL) 452 rv = DO_1PASS_TEST(passwd, &td, 453 passwd_test_getpwuid, (void *)&td); 454 else 455 rv = DO_1PASS_TEST(passwd, &td_snap, 456 passwd_test_getpwuid, (void *)&td_snap); 457 break; 458 case TEST_GETPWENT: 459 if (snapshot_file == NULL) 460 rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent, 461 (void *)&td); 462 else 463 rv = DO_2PASS_TEST(passwd, &td, &td_snap, 464 compare_passwd, NULL); 465 break; 466 case TEST_GETPWENT_2PASS: 467 TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd); 468 rv = passwd_fill_test_data(&td_2pass); 469 if (rv != -1) 470 rv = DO_2PASS_TEST(passwd, &td, &td_2pass, 471 compare_passwd, NULL); 472 TEST_DATA_DESTROY(passwd, &td_2pass); 473 break; 474 case TEST_BUILD_SNAPSHOT: 475 if (snapshot_file != NULL) 476 rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file, &td, 477 sdump_passwd); 478 break; 479 default: 480 rv = 0; 481 break; 482 }; 483 484fin: 485 TEST_DATA_DESTROY(passwd, &td_snap); 486 TEST_DATA_DESTROY(passwd, &td); 487 free(snapshot_file); 488 return (rv); 489} 490