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