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