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 <arpa/inet.h> 29 #include <errno.h> 30 #include <netdb.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <stringlist.h> 35 #include <unistd.h> 36 37 #include <atf-c.h> 38 39 #include "testutil.h" 40 41 enum test_methods { 42 TEST_GETSERVENT, 43 TEST_GETSERVBYNAME, 44 TEST_GETSERVBYPORT, 45 TEST_GETSERVENT_2PASS, 46 TEST_BUILD_SNAPSHOT 47 }; 48 49 DECLARE_TEST_DATA(servent) 50 DECLARE_TEST_FILE_SNAPSHOT(servent) 51 DECLARE_1PASS_TEST(servent) 52 DECLARE_2PASS_TEST(servent) 53 54 static void clone_servent(struct servent *, struct servent const *); 55 static int compare_servent(struct servent *, struct servent *, void *); 56 static void dump_servent(struct servent *); 57 static void free_servent(struct servent *); 58 59 static void sdump_servent(struct servent *, char *, size_t); 60 static int servent_read_snapshot_func(struct servent *, char *); 61 62 static int servent_check_ambiguity(struct servent_test_data *, 63 struct servent *); 64 static int servent_fill_test_data(struct servent_test_data *); 65 static int servent_test_correctness(struct servent *, void *); 66 static int servent_test_getservbyname(struct servent *, void *); 67 static int servent_test_getservbyport(struct servent *, void *); 68 static int servent_test_getservent(struct servent *, void *); 69 70 IMPLEMENT_TEST_DATA(servent) 71 IMPLEMENT_TEST_FILE_SNAPSHOT(servent) 72 IMPLEMENT_1PASS_TEST(servent) 73 IMPLEMENT_2PASS_TEST(servent) 74 75 static void 76 clone_servent(struct servent *dest, struct servent const *src) 77 { 78 ATF_REQUIRE(dest != NULL); 79 ATF_REQUIRE(src != NULL); 80 81 char **cp; 82 int aliases_num; 83 84 memset(dest, 0, sizeof(struct servent)); 85 86 if (src->s_name != NULL) { 87 dest->s_name = strdup(src->s_name); 88 ATF_REQUIRE(dest->s_name != NULL); 89 } 90 91 if (src->s_proto != NULL) { 92 dest->s_proto = strdup(src->s_proto); 93 ATF_REQUIRE(dest->s_proto != NULL); 94 } 95 dest->s_port = src->s_port; 96 97 if (src->s_aliases != NULL) { 98 aliases_num = 0; 99 for (cp = src->s_aliases; *cp; ++cp) 100 ++aliases_num; 101 102 dest->s_aliases = calloc(aliases_num + 1, sizeof(char *)); 103 ATF_REQUIRE(dest->s_aliases != NULL); 104 105 for (cp = src->s_aliases; *cp; ++cp) { 106 dest->s_aliases[cp - src->s_aliases] = strdup(*cp); 107 ATF_REQUIRE(dest->s_aliases[cp - src->s_aliases] != NULL); 108 } 109 } 110 } 111 112 static void 113 free_servent(struct servent *serv) 114 { 115 char **cp; 116 117 ATF_REQUIRE(serv != NULL); 118 119 free(serv->s_name); 120 free(serv->s_proto); 121 122 for (cp = serv->s_aliases; *cp; ++cp) 123 free(*cp); 124 free(serv->s_aliases); 125 } 126 127 static int 128 compare_servent(struct servent *serv1, struct servent *serv2, void *mdata) 129 { 130 char **c1, **c2; 131 132 if (serv1 == serv2) 133 return 0; 134 135 if ((serv1 == NULL) || (serv2 == NULL)) 136 goto errfin; 137 138 if ((strcmp(serv1->s_name, serv2->s_name) != 0) || 139 (strcmp(serv1->s_proto, serv2->s_proto) != 0) || 140 (serv1->s_port != serv2->s_port)) 141 goto errfin; 142 143 c1 = serv1->s_aliases; 144 c2 = serv2->s_aliases; 145 146 if ((serv1->s_aliases == NULL) || (serv2->s_aliases == NULL)) 147 goto errfin; 148 149 for (;*c1 && *c2; ++c1, ++c2) 150 if (strcmp(*c1, *c2) != 0) 151 goto errfin; 152 153 if ((*c1 != NULL) || (*c2 != NULL)) 154 goto errfin; 155 156 return 0; 157 158 errfin: 159 if (mdata == NULL) { 160 printf("following structures are not equal:\n"); 161 dump_servent(serv1); 162 dump_servent(serv2); 163 } 164 165 return (-1); 166 } 167 168 static void 169 sdump_servent(struct servent *serv, char *buffer, size_t buflen) 170 { 171 char **cp; 172 int written; 173 174 written = snprintf(buffer, buflen, "%s %d %s", 175 serv->s_name, ntohs(serv->s_port), serv->s_proto); 176 buffer += written; 177 if (written > (int)buflen) 178 return; 179 buflen -= written; 180 181 if (serv->s_aliases != NULL) { 182 if (*(serv->s_aliases) != NULL) { 183 for (cp = serv->s_aliases; *cp; ++cp) { 184 written = snprintf(buffer, buflen, " %s", *cp); 185 buffer += written; 186 if (written > (int)buflen) 187 return; 188 buflen -= written; 189 190 if (buflen == 0) 191 return; 192 } 193 } else 194 snprintf(buffer, buflen, " noaliases"); 195 } else 196 snprintf(buffer, buflen, " (null)"); 197 } 198 199 static int 200 servent_read_snapshot_func(struct servent *serv, char *line) 201 { 202 StringList *sl; 203 char *s, *ps, *ts; 204 int i; 205 206 printf("1 line read from snapshot:\n%s\n", line); 207 208 i = 0; 209 sl = NULL; 210 ps = line; 211 memset(serv, 0, sizeof(struct servent)); 212 while ( (s = strsep(&ps, " ")) != NULL) { 213 switch (i) { 214 case 0: 215 serv->s_name = strdup(s); 216 ATF_REQUIRE(serv->s_name != NULL); 217 break; 218 219 case 1: 220 serv->s_port = htons( 221 (int)strtol(s, &ts, 10)); 222 if (*ts != '\0') { 223 free(serv->s_name); 224 return (-1); 225 } 226 break; 227 228 case 2: 229 serv->s_proto = strdup(s); 230 ATF_REQUIRE(serv->s_proto != NULL); 231 break; 232 233 default: 234 if (sl == NULL) { 235 if (strcmp(s, "(null)") == 0) 236 return (0); 237 238 sl = sl_init(); 239 ATF_REQUIRE(sl != NULL); 240 241 if (strcmp(s, "noaliases") != 0) { 242 ts = strdup(s); 243 ATF_REQUIRE(ts != NULL); 244 sl_add(sl, ts); 245 } 246 } else { 247 ts = strdup(s); 248 ATF_REQUIRE(ts != NULL); 249 sl_add(sl, ts); 250 } 251 break; 252 } 253 ++i; 254 } 255 256 if (i < 3) { 257 free(serv->s_name); 258 free(serv->s_proto); 259 memset(serv, 0, sizeof(struct servent)); 260 return (-1); 261 } 262 263 sl_add(sl, NULL); 264 serv->s_aliases = sl->sl_str; 265 266 /* NOTE: is it a dirty hack or not? */ 267 free(sl); 268 return (0); 269 } 270 271 static void 272 dump_servent(struct servent *result) 273 { 274 if (result != NULL) { 275 char buffer[1024]; 276 sdump_servent(result, buffer, sizeof(buffer)); 277 printf("%s\n", buffer); 278 } else 279 printf("(null)\n"); 280 } 281 282 static int 283 servent_fill_test_data(struct servent_test_data *td) 284 { 285 struct servent *serv; 286 287 setservent(1); 288 while ((serv = getservent()) != NULL) { 289 if (servent_test_correctness(serv, NULL) == 0) 290 TEST_DATA_APPEND(servent, td, serv); 291 else 292 return (-1); 293 } 294 endservent(); 295 296 return (0); 297 } 298 299 static int 300 servent_test_correctness(struct servent *serv, void *mdata __unused) 301 { 302 printf("testing correctness with the following data:\n"); 303 dump_servent(serv); 304 305 if (serv == NULL) 306 goto errfin; 307 308 if (serv->s_name == NULL) 309 goto errfin; 310 311 if (serv->s_proto == NULL) 312 goto errfin; 313 314 if (ntohs(serv->s_port < 0)) 315 goto errfin; 316 317 if (serv->s_aliases == NULL) 318 goto errfin; 319 320 printf("correct\n"); 321 322 return (0); 323 errfin: 324 printf("incorrect\n"); 325 326 return (-1); 327 } 328 329 /* servent_check_ambiguity() is needed when one port+proto is associated with 330 * more than one service (these cases are usually marked as PROBLEM in 331 * /etc/services. This functions is needed also when one service+proto is 332 * associated with several ports. We have to check all the servent structures 333 * to make sure that serv really exists and correct */ 334 static int 335 servent_check_ambiguity(struct servent_test_data *td, struct servent *serv) 336 { 337 338 return (TEST_DATA_FIND(servent, td, serv, compare_servent, 339 NULL) != NULL ? 0 : -1); 340 } 341 342 static int 343 servent_test_getservbyname(struct servent *serv_model, void *mdata) 344 { 345 char **alias; 346 struct servent *serv; 347 348 printf("testing getservbyname() with the following data:\n"); 349 dump_servent(serv_model); 350 351 serv = getservbyname(serv_model->s_name, serv_model->s_proto); 352 if (servent_test_correctness(serv, NULL) != 0) 353 goto errfin; 354 355 if ((compare_servent(serv, serv_model, NULL) != 0) && 356 (servent_check_ambiguity((struct servent_test_data *)mdata, serv) 357 !=0)) 358 goto errfin; 359 360 for (alias = serv_model->s_aliases; *alias; ++alias) { 361 serv = getservbyname(*alias, serv_model->s_proto); 362 363 if (servent_test_correctness(serv, NULL) != 0) 364 goto errfin; 365 366 if ((compare_servent(serv, serv_model, NULL) != 0) && 367 (servent_check_ambiguity( 368 (struct servent_test_data *)mdata, serv) != 0)) 369 goto errfin; 370 } 371 372 printf("ok\n"); 373 return (0); 374 375 errfin: 376 printf("not ok\n"); 377 378 return (-1); 379 } 380 381 static int 382 servent_test_getservbyport(struct servent *serv_model, void *mdata) 383 { 384 struct servent *serv; 385 386 printf("testing getservbyport() with the following data...\n"); 387 dump_servent(serv_model); 388 389 serv = getservbyport(serv_model->s_port, serv_model->s_proto); 390 if ((servent_test_correctness(serv, NULL) != 0) || 391 ((compare_servent(serv, serv_model, NULL) != 0) && 392 (servent_check_ambiguity((struct servent_test_data *)mdata, serv) 393 != 0))) { 394 printf("not ok\n"); 395 return (-1); 396 } else { 397 printf("ok\n"); 398 return (0); 399 } 400 } 401 402 static int 403 servent_test_getservent(struct servent *serv, void *mdata __unused) 404 { 405 /* Only correctness can be checked when doing 1-pass test for 406 * getservent(). */ 407 return (servent_test_correctness(serv, NULL)); 408 } 409 410 static int 411 run_tests(const char *snapshot_file, enum test_methods method) 412 { 413 struct servent_test_data td, td_snap, td_2pass; 414 int rv; 415 416 TEST_DATA_INIT(servent, &td, clone_servent, free_servent); 417 TEST_DATA_INIT(servent, &td_snap, clone_servent, free_servent); 418 if (snapshot_file != NULL) { 419 if (access(snapshot_file, W_OK | R_OK) != 0) { 420 if (errno == ENOENT) 421 method = TEST_BUILD_SNAPSHOT; 422 else { 423 printf("can't access the file %s\n", 424 snapshot_file); 425 426 rv = -1; 427 goto fin; 428 } 429 } else { 430 if (method == TEST_BUILD_SNAPSHOT) { 431 rv = 0; 432 goto fin; 433 } 434 435 TEST_SNAPSHOT_FILE_READ(servent, snapshot_file, 436 &td_snap, servent_read_snapshot_func); 437 } 438 } 439 440 rv = servent_fill_test_data(&td); 441 if (rv == -1) 442 return (-1); 443 switch (method) { 444 case TEST_GETSERVBYNAME: 445 if (snapshot_file == NULL) 446 rv = DO_1PASS_TEST(servent, &td, 447 servent_test_getservbyname, (void *)&td); 448 else 449 rv = DO_1PASS_TEST(servent, &td_snap, 450 servent_test_getservbyname, (void *)&td_snap); 451 break; 452 case TEST_GETSERVBYPORT: 453 if (snapshot_file == NULL) 454 rv = DO_1PASS_TEST(servent, &td, 455 servent_test_getservbyport, (void *)&td); 456 else 457 rv = DO_1PASS_TEST(servent, &td_snap, 458 servent_test_getservbyport, (void *)&td_snap); 459 break; 460 case TEST_GETSERVENT: 461 if (snapshot_file == NULL) 462 rv = DO_1PASS_TEST(servent, &td, servent_test_getservent, 463 (void *)&td); 464 else 465 rv = DO_2PASS_TEST(servent, &td, &td_snap, 466 compare_servent, NULL); 467 break; 468 case TEST_GETSERVENT_2PASS: 469 TEST_DATA_INIT(servent, &td_2pass, clone_servent, free_servent); 470 rv = servent_fill_test_data(&td_2pass); 471 if (rv != -1) 472 rv = DO_2PASS_TEST(servent, &td, &td_2pass, 473 compare_servent, NULL); 474 TEST_DATA_DESTROY(servent, &td_2pass); 475 break; 476 case TEST_BUILD_SNAPSHOT: 477 if (snapshot_file != NULL) 478 rv = TEST_SNAPSHOT_FILE_WRITE(servent, snapshot_file, &td, 479 sdump_servent); 480 break; 481 default: 482 rv = 0; 483 break; 484 } 485 486 fin: 487 TEST_DATA_DESTROY(servent, &td_snap); 488 TEST_DATA_DESTROY(servent, &td); 489 490 return (rv); 491 } 492 493 #define SNAPSHOT_FILE "snapshot_serv" 494 495 ATF_TC_WITHOUT_HEAD(build_snapshot); 496 ATF_TC_BODY(build_snapshot, tc) 497 { 498 499 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 500 } 501 502 ATF_TC_WITHOUT_HEAD(getservbyname); 503 ATF_TC_BODY(getservbyname, tc) 504 { 505 506 ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYNAME) == 0); 507 } 508 509 ATF_TC_WITHOUT_HEAD(getservbyname_with_snapshot); 510 ATF_TC_BODY(getservbyname_with_snapshot, tc) 511 { 512 513 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 514 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYNAME) == 0); 515 } 516 517 ATF_TC_WITHOUT_HEAD(getservbyport); 518 ATF_TC_BODY(getservbyport, tc) 519 { 520 521 ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYPORT) == 0); 522 } 523 524 ATF_TC_WITHOUT_HEAD(getservbyport_with_snapshot); 525 ATF_TC_BODY(getservbyport_with_snapshot, tc) 526 { 527 528 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 529 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYPORT) == 0); 530 } 531 532 ATF_TC_WITHOUT_HEAD(getservbyent); 533 ATF_TC_BODY(getservbyent, tc) 534 { 535 536 ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT) == 0); 537 } 538 539 ATF_TC_WITHOUT_HEAD(getservbyent_with_snapshot); 540 ATF_TC_BODY(getservbyent_with_snapshot, tc) 541 { 542 543 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 544 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVENT) == 0); 545 } 546 547 ATF_TC_WITHOUT_HEAD(getservbyent_with_two_pass); 548 ATF_TC_BODY(getservbyent_with_two_pass, tc) 549 { 550 551 ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT_2PASS) == 0); 552 } 553 554 ATF_TP_ADD_TCS(tp) 555 { 556 557 ATF_TP_ADD_TC(tp, build_snapshot); 558 ATF_TP_ADD_TC(tp, getservbyent); 559 ATF_TP_ADD_TC(tp, getservbyent_with_snapshot); 560 ATF_TP_ADD_TC(tp, getservbyent_with_two_pass); 561 ATF_TP_ADD_TC(tp, getservbyname); 562 ATF_TP_ADD_TC(tp, getservbyname_with_snapshot); 563 ATF_TP_ADD_TC(tp, getservbyport); 564 ATF_TP_ADD_TC(tp, getservbyport_with_snapshot); 565 566 return (atf_no_error()); 567 } 568