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