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