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