]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - lib/libc/tests/nss/getserv_test.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / lib / libc / tests / nss / getserv_test.c
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 <errno.h>
33 #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
44 enum test_methods {
45         TEST_GETSERVENT,
46         TEST_GETSERVBYNAME,
47         TEST_GETSERVBYPORT,
48         TEST_GETSERVENT_2PASS,
49         TEST_BUILD_SNAPSHOT
50 };
51
52 DECLARE_TEST_DATA(servent)
53 DECLARE_TEST_FILE_SNAPSHOT(servent)
54 DECLARE_1PASS_TEST(servent)
55 DECLARE_2PASS_TEST(servent)
56
57 static void clone_servent(struct servent *, struct servent const *);
58 static int compare_servent(struct servent *, struct servent *, void *);
59 static void dump_servent(struct servent *);
60 static void free_servent(struct servent *);
61
62 static void sdump_servent(struct servent *, char *, size_t);
63 static int servent_read_snapshot_func(struct servent *, char *);
64
65 static int servent_check_ambiguity(struct servent_test_data *,
66         struct servent *);
67 static int servent_fill_test_data(struct servent_test_data *);
68 static int servent_test_correctness(struct servent *, void *);
69 static int servent_test_getservbyname(struct servent *, void *);
70 static int servent_test_getservbyport(struct servent *, void *);
71 static int servent_test_getservent(struct servent *, void *);
72
73 IMPLEMENT_TEST_DATA(servent)
74 IMPLEMENT_TEST_FILE_SNAPSHOT(servent)
75 IMPLEMENT_1PASS_TEST(servent)
76 IMPLEMENT_2PASS_TEST(servent)
77
78 static void
79 clone_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(1, (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
115 static void
116 free_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
130 static  int
131 compare_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
161 errfin:
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
171 static void
172 sdump_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 > 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 > 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
202 static int
203 servent_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
274 static void
275 dump_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
285 static int
286 servent_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
302 static int
303 servent_test_correctness(struct servent *serv, void *mdata)
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);
326 errfin:
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 */
337 static int
338 servent_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
345 static int
346 servent_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
378 errfin:
379         printf("not ok\n");
380
381         return (-1);
382 }
383
384 static int
385 servent_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
405 static int
406 servent_test_getservent(struct servent *serv, void *mdata)
407 {
408         /* Only correctness can be checked when doing 1-pass test for
409          * getservent(). */
410         return (servent_test_correctness(serv, NULL));
411 }
412
413 int
414 run_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
489 fin:
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
498 ATF_TC_WITHOUT_HEAD(build_snapshot);
499 ATF_TC_BODY(build_snapshot, tc)
500 {
501
502         ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
503 }
504
505 ATF_TC_WITHOUT_HEAD(getservbyname);
506 ATF_TC_BODY(getservbyname, tc)
507 {
508
509         ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYNAME) == 0);
510 }
511
512 ATF_TC_WITHOUT_HEAD(getservbyname_with_snapshot);
513 ATF_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
520 ATF_TC_WITHOUT_HEAD(getservbyport);
521 ATF_TC_BODY(getservbyport, tc)
522 {
523
524         ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYPORT) == 0);
525 }
526
527 ATF_TC_WITHOUT_HEAD(getservbyport_with_snapshot);
528 ATF_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
535 ATF_TC_WITHOUT_HEAD(getservbyent);
536 ATF_TC_BODY(getservbyent, tc)
537 {
538
539         ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT) == 0);
540 }
541
542 ATF_TC_WITHOUT_HEAD(getservbyent_with_snapshot);
543 ATF_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
550 ATF_TC_WITHOUT_HEAD(getservbyent_with_two_pass);
551 ATF_TC_BODY(getservbyent_with_two_pass, tc)
552 {
553
554         ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT_2PASS) == 0);
555 }
556
557 ATF_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 }