Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/net/getservent.c
39476 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1983, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
* 3. Neither the name of the University nor the names of its contributors
16
* may be used to endorse or promote products derived from this software
17
* without specific prior written permission.
18
*
19
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
* SUCH DAMAGE.
30
*/
31
32
#include <sys/param.h>
33
#include <sys/socket.h>
34
#include <arpa/inet.h>
35
#include <db.h>
36
#include <errno.h>
37
#include <fcntl.h>
38
#include <limits.h>
39
#include <netdb.h>
40
#include <nsswitch.h>
41
#include <stdio.h>
42
#include <string.h>
43
#include <stdlib.h>
44
#include <unistd.h>
45
#ifdef YP
46
#include <rpc/rpc.h>
47
#include <rpcsvc/yp_prot.h>
48
#include <rpcsvc/ypclnt.h>
49
#endif
50
#include "namespace.h"
51
#include "reentrant.h"
52
#include "un-namespace.h"
53
#include "netdb_private.h"
54
#ifdef NS_CACHING
55
#include "nscache.h"
56
#endif
57
#include "nss_tls.h"
58
59
enum constants
60
{
61
SETSERVENT = 1,
62
ENDSERVENT = 2,
63
SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
64
SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
65
};
66
67
struct servent_mdata
68
{
69
enum nss_lookup_type how;
70
int compat_mode;
71
};
72
73
static const ns_src defaultsrc[] = {
74
{ NSSRC_COMPAT, NS_SUCCESS },
75
{ NULL, 0 }
76
};
77
78
static int servent_unpack(char *, struct servent *, char **, size_t, int *);
79
80
/* files backend declarations */
81
struct files_state
82
{
83
FILE *fp;
84
int stayopen;
85
86
int compat_mode_active;
87
};
88
static void files_endstate(void *);
89
NSS_TLS_HANDLING(files);
90
91
static int files_servent(void *, void *, va_list);
92
static int files_setservent(void *, void *, va_list);
93
94
/* db backend declarations */
95
struct db_state
96
{
97
DB *db;
98
int stayopen;
99
int keynum;
100
};
101
static void db_endstate(void *);
102
NSS_TLS_HANDLING(db);
103
104
static int db_servent(void *, void *, va_list);
105
static int db_setservent(void *, void *, va_list);
106
107
#ifdef YP
108
/* nis backend declarations */
109
static int nis_servent(void *, void *, va_list);
110
static int nis_setservent(void *, void *, va_list);
111
112
struct nis_state
113
{
114
int yp_stepping;
115
char yp_domain[MAXHOSTNAMELEN];
116
char *yp_key;
117
int yp_keylen;
118
};
119
static void nis_endstate(void *);
120
NSS_TLS_HANDLING(nis);
121
122
static int nis_servent(void *, void *, va_list);
123
static int nis_setservent(void *, void *, va_list);
124
#endif
125
126
/* compat backend declarations */
127
static int compat_setservent(void *, void *, va_list);
128
129
/* get** wrappers for get**_r functions declarations */
130
struct servent_state {
131
struct servent serv;
132
char *buffer;
133
size_t bufsize;
134
};
135
static void servent_endstate(void *);
136
NSS_TLS_HANDLING(servent);
137
138
struct key {
139
const char *proto;
140
union {
141
const char *name;
142
int port;
143
};
144
};
145
146
static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t,
147
struct servent **);
148
static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t,
149
struct servent **);
150
static int wrap_getservent_r(struct key, struct servent *, char *, size_t,
151
struct servent **);
152
static struct servent *getserv(int (*fn)(struct key, struct servent *, char *,
153
size_t, struct servent **), struct key);
154
155
#ifdef NS_CACHING
156
static int serv_id_func(char *, size_t *, va_list, void *);
157
static int serv_marshal_func(char *, size_t *, void *, va_list, void *);
158
static int serv_unmarshal_func(char *, size_t, void *, va_list, void *);
159
#endif
160
161
static int
162
servent_unpack(char *p, struct servent *serv, char **aliases,
163
size_t aliases_size, int *errnop)
164
{
165
char *cp, **q, *endp;
166
long l;
167
168
if (*p == '#')
169
return -1;
170
171
memset(serv, 0, sizeof(struct servent));
172
173
cp = strpbrk(p, "#\n");
174
if (cp != NULL)
175
*cp = '\0';
176
serv->s_name = p;
177
178
p = strpbrk(p, " \t");
179
if (p == NULL)
180
return -1;
181
*p++ = '\0';
182
while (*p == ' ' || *p == '\t')
183
p++;
184
cp = strpbrk(p, ",/");
185
if (cp == NULL)
186
return -1;
187
188
*cp++ = '\0';
189
l = strtol(p, &endp, 10);
190
if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX)
191
return -1;
192
serv->s_port = htons((in_port_t)l);
193
serv->s_proto = cp;
194
195
q = serv->s_aliases = aliases;
196
cp = strpbrk(cp, " \t");
197
if (cp != NULL)
198
*cp++ = '\0';
199
while (cp && *cp) {
200
if (*cp == ' ' || *cp == '\t') {
201
cp++;
202
continue;
203
}
204
if (q < &aliases[aliases_size - 1]) {
205
*q++ = cp;
206
} else {
207
*q = NULL;
208
*errnop = ERANGE;
209
return -1;
210
}
211
cp = strpbrk(cp, " \t");
212
if (cp != NULL)
213
*cp++ = '\0';
214
}
215
*q = NULL;
216
217
return 0;
218
}
219
220
static int
221
parse_result(struct servent *serv, char *buffer, size_t bufsize,
222
char *resultbuf, size_t resultbuflen, int *errnop)
223
{
224
char **aliases;
225
int aliases_size;
226
227
if (bufsize <= resultbuflen + _ALIGNBYTES + sizeof(char *)) {
228
*errnop = ERANGE;
229
return (NS_RETURN);
230
}
231
aliases = (char **)_ALIGN(&buffer[resultbuflen + 1]);
232
aliases_size = (buffer + bufsize - (char *)aliases) / sizeof(char *);
233
if (aliases_size < 1) {
234
*errnop = ERANGE;
235
return (NS_RETURN);
236
}
237
238
memcpy(buffer, resultbuf, resultbuflen);
239
buffer[resultbuflen] = '\0';
240
241
if (servent_unpack(buffer, serv, aliases, aliases_size, errnop) != 0)
242
return ((*errnop == 0) ? NS_NOTFOUND : NS_RETURN);
243
return (NS_SUCCESS);
244
}
245
246
/* files backend implementation */
247
static void
248
files_endstate(void *p)
249
{
250
FILE * f;
251
252
if (p == NULL)
253
return;
254
255
f = ((struct files_state *)p)->fp;
256
if (f != NULL)
257
fclose(f);
258
259
free(p);
260
}
261
262
/*
263
* compat structures. compat and files sources functionalities are almost
264
* equal, so they all are managed by files_servent function
265
*/
266
static int
267
files_servent(void *retval, void *mdata, va_list ap)
268
{
269
static const ns_src compat_src[] = {
270
#ifdef YP
271
{ NSSRC_NIS, NS_SUCCESS },
272
#endif
273
{ NULL, 0 }
274
};
275
ns_dtab compat_dtab[] = {
276
{ NSSRC_DB, db_servent,
277
(void *)((struct servent_mdata *)mdata)->how },
278
#ifdef YP
279
{ NSSRC_NIS, nis_servent,
280
(void *)((struct servent_mdata *)mdata)->how },
281
#endif
282
{ NULL, NULL, NULL }
283
};
284
285
struct files_state *st;
286
int rv;
287
int stayopen;
288
289
struct servent_mdata *serv_mdata;
290
char *name;
291
char *proto;
292
int port;
293
294
struct servent *serv;
295
char *buffer;
296
size_t bufsize;
297
int *errnop;
298
299
size_t linesize;
300
char *line;
301
char **cp;
302
303
name = NULL;
304
proto = NULL;
305
serv_mdata = (struct servent_mdata *)mdata;
306
switch (serv_mdata->how) {
307
case nss_lt_name:
308
name = va_arg(ap, char *);
309
proto = va_arg(ap, char *);
310
break;
311
case nss_lt_id:
312
port = va_arg(ap, int);
313
proto = va_arg(ap, char *);
314
break;
315
case nss_lt_all:
316
break;
317
default:
318
return NS_NOTFOUND;
319
}
320
321
serv = va_arg(ap, struct servent *);
322
buffer = va_arg(ap, char *);
323
bufsize = va_arg(ap, size_t);
324
errnop = va_arg(ap,int *);
325
326
*errnop = files_getstate(&st);
327
if (*errnop != 0)
328
return (NS_UNAVAIL);
329
330
if (st->fp == NULL)
331
st->compat_mode_active = 0;
332
333
if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "re")) == NULL) {
334
*errnop = errno;
335
return (NS_UNAVAIL);
336
}
337
338
if (serv_mdata->how == nss_lt_all)
339
stayopen = 1;
340
else {
341
rewind(st->fp);
342
stayopen = st->stayopen;
343
}
344
345
rv = NS_NOTFOUND;
346
do {
347
if (!st->compat_mode_active) {
348
if ((line = fgetln(st->fp, &linesize)) == NULL) {
349
*errnop = errno;
350
rv = NS_RETURN;
351
break;
352
}
353
354
if (*line=='+' && serv_mdata->compat_mode != 0)
355
st->compat_mode_active = 1;
356
}
357
358
if (st->compat_mode_active != 0) {
359
switch (serv_mdata->how) {
360
case nss_lt_name:
361
rv = nsdispatch(retval, compat_dtab,
362
NSDB_SERVICES_COMPAT, "getservbyname_r",
363
compat_src, name, proto, serv, buffer,
364
bufsize, errnop);
365
break;
366
case nss_lt_id:
367
rv = nsdispatch(retval, compat_dtab,
368
NSDB_SERVICES_COMPAT, "getservbyport_r",
369
compat_src, port, proto, serv, buffer,
370
bufsize, errnop);
371
break;
372
case nss_lt_all:
373
rv = nsdispatch(retval, compat_dtab,
374
NSDB_SERVICES_COMPAT, "getservent_r",
375
compat_src, serv, buffer, bufsize, errnop);
376
break;
377
}
378
379
if (!(rv & NS_TERMINATE) ||
380
serv_mdata->how != nss_lt_all)
381
st->compat_mode_active = 0;
382
383
continue;
384
}
385
386
rv = parse_result(serv, buffer, bufsize, line, linesize,
387
errnop);
388
if (rv == NS_NOTFOUND)
389
continue;
390
if (rv == NS_RETURN)
391
break;
392
393
rv = NS_NOTFOUND;
394
switch (serv_mdata->how) {
395
case nss_lt_name:
396
if (strcmp(name, serv->s_name) == 0)
397
goto gotname;
398
for (cp = serv->s_aliases; *cp; cp++)
399
if (strcmp(name, *cp) == 0)
400
goto gotname;
401
402
continue;
403
gotname:
404
if (proto == NULL || strcmp(serv->s_proto, proto) == 0)
405
rv = NS_SUCCESS;
406
break;
407
case nss_lt_id:
408
if (port != serv->s_port)
409
continue;
410
411
if (proto == NULL || strcmp(serv->s_proto, proto) == 0)
412
rv = NS_SUCCESS;
413
break;
414
case nss_lt_all:
415
rv = NS_SUCCESS;
416
break;
417
}
418
419
} while (!(rv & NS_TERMINATE));
420
421
if (!stayopen && st->fp != NULL) {
422
fclose(st->fp);
423
st->fp = NULL;
424
}
425
426
if ((rv == NS_SUCCESS) && (retval != NULL))
427
*(struct servent **)retval=serv;
428
429
return (rv);
430
}
431
432
static int
433
files_setservent(void *retval, void *mdata, va_list ap)
434
{
435
struct files_state *st;
436
int rv;
437
int f;
438
439
rv = files_getstate(&st);
440
if (rv != 0)
441
return (NS_UNAVAIL);
442
443
switch ((enum constants)(uintptr_t)mdata) {
444
case SETSERVENT:
445
f = va_arg(ap,int);
446
if (st->fp == NULL)
447
st->fp = fopen(_PATH_SERVICES, "re");
448
else
449
rewind(st->fp);
450
st->stayopen |= f;
451
break;
452
case ENDSERVENT:
453
if (st->fp != NULL) {
454
fclose(st->fp);
455
st->fp = NULL;
456
}
457
st->stayopen = 0;
458
break;
459
default:
460
break;
461
}
462
463
st->compat_mode_active = 0;
464
return (NS_UNAVAIL);
465
}
466
467
/* db backend implementation */
468
static void
469
db_endstate(void *p)
470
{
471
DB *db;
472
473
if (p == NULL)
474
return;
475
476
db = ((struct db_state *)p)->db;
477
if (db != NULL)
478
db->close(db);
479
480
free(p);
481
}
482
483
static int
484
db_servent(void *retval, void *mdata, va_list ap)
485
{
486
char buf[BUFSIZ];
487
DBT key, data, *result;
488
DB *db;
489
490
struct db_state *st;
491
int rv;
492
int stayopen;
493
494
enum nss_lookup_type how;
495
char *name;
496
char *proto;
497
int port;
498
499
struct servent *serv;
500
char *buffer;
501
size_t bufsize;
502
int *errnop;
503
504
name = NULL;
505
proto = NULL;
506
how = (enum nss_lookup_type)(uintptr_t)mdata;
507
switch (how) {
508
case nss_lt_name:
509
name = va_arg(ap, char *);
510
proto = va_arg(ap, char *);
511
break;
512
case nss_lt_id:
513
port = va_arg(ap, int);
514
proto = va_arg(ap, char *);
515
break;
516
case nss_lt_all:
517
break;
518
default:
519
return NS_NOTFOUND;
520
}
521
522
serv = va_arg(ap, struct servent *);
523
buffer = va_arg(ap, char *);
524
bufsize = va_arg(ap, size_t);
525
errnop = va_arg(ap,int *);
526
527
*errnop = db_getstate(&st);
528
if (*errnop != 0)
529
return (NS_UNAVAIL);
530
531
if (how == nss_lt_all && st->keynum < 0)
532
return (NS_NOTFOUND);
533
534
if (st->db == NULL) {
535
st->db = dbopen(_PATH_SERVICES_DB, O_RDONLY, 0, DB_HASH, NULL);
536
if (st->db == NULL) {
537
*errnop = errno;
538
return (NS_UNAVAIL);
539
}
540
}
541
542
stayopen = (how == nss_lt_all) ? 1 : st->stayopen;
543
db = st->db;
544
545
do {
546
switch (how) {
547
case nss_lt_name:
548
key.data = buf;
549
if (proto == NULL)
550
key.size = snprintf(buf, sizeof(buf),
551
"\376%s", name);
552
else
553
key.size = snprintf(buf, sizeof(buf),
554
"\376%s/%s", name, proto);
555
key.size++;
556
if (db->get(db, &key, &data, 0) != 0 ||
557
db->get(db, &data, &key, 0) != 0) {
558
rv = NS_NOTFOUND;
559
goto db_fin;
560
}
561
result = &key;
562
break;
563
case nss_lt_id:
564
key.data = buf;
565
port = htons(port);
566
if (proto == NULL)
567
key.size = snprintf(buf, sizeof(buf),
568
"\377%d", port);
569
else
570
key.size = snprintf(buf, sizeof(buf),
571
"\377%d/%s", port, proto);
572
key.size++;
573
if (db->get(db, &key, &data, 0) != 0 ||
574
db->get(db, &data, &key, 0) != 0) {
575
rv = NS_NOTFOUND;
576
goto db_fin;
577
}
578
result = &key;
579
break;
580
case nss_lt_all:
581
key.data = buf;
582
key.size = snprintf(buf, sizeof(buf), "%d",
583
st->keynum++);
584
key.size++;
585
if (db->get(db, &key, &data, 0) != 0) {
586
st->keynum = -1;
587
rv = NS_NOTFOUND;
588
goto db_fin;
589
}
590
result = &data;
591
break;
592
}
593
594
rv = parse_result(serv, buffer, bufsize, result->data,
595
result->size - 1, errnop);
596
597
} while (!(rv & NS_TERMINATE) && how == nss_lt_all);
598
599
db_fin:
600
if (!stayopen && st->db != NULL) {
601
db->close(db);
602
st->db = NULL;
603
}
604
605
if (rv == NS_SUCCESS && retval != NULL)
606
*(struct servent **)retval = serv;
607
608
return (rv);
609
}
610
611
static int
612
db_setservent(void *retval, void *mdata, va_list ap)
613
{
614
DB *db;
615
struct db_state *st;
616
int rv;
617
int f;
618
619
rv = db_getstate(&st);
620
if (rv != 0)
621
return (NS_UNAVAIL);
622
623
switch ((enum constants)(uintptr_t)mdata) {
624
case SETSERVENT:
625
f = va_arg(ap, int);
626
st->stayopen |= f;
627
st->keynum = 0;
628
break;
629
case ENDSERVENT:
630
db = st->db;
631
if (db != NULL) {
632
db->close(db);
633
st->db = NULL;
634
}
635
st->stayopen = 0;
636
break;
637
default:
638
break;
639
}
640
641
return (NS_UNAVAIL);
642
}
643
644
/* nis backend implementation */
645
#ifdef YP
646
static void
647
nis_endstate(void *p)
648
{
649
if (p == NULL)
650
return;
651
652
free(((struct nis_state *)p)->yp_key);
653
free(p);
654
}
655
656
static int
657
nis_servent(void *retval, void *mdata, va_list ap)
658
{
659
char *resultbuf, *lastkey;
660
int resultbuflen;
661
char *buf;
662
663
struct nis_state *st;
664
int rv;
665
666
enum nss_lookup_type how;
667
char *name;
668
char *proto;
669
int port;
670
671
struct servent *serv;
672
char *buffer;
673
size_t bufsize;
674
int *errnop;
675
676
name = NULL;
677
proto = NULL;
678
buf = NULL;
679
how = (enum nss_lookup_type)(uintptr_t)mdata;
680
switch (how) {
681
case nss_lt_name:
682
name = va_arg(ap, char *);
683
proto = va_arg(ap, char *);
684
break;
685
case nss_lt_id:
686
port = va_arg(ap, int);
687
proto = va_arg(ap, char *);
688
break;
689
case nss_lt_all:
690
break;
691
default:
692
return NS_NOTFOUND;
693
}
694
695
serv = va_arg(ap, struct servent *);
696
buffer = va_arg(ap, char *);
697
bufsize = va_arg(ap, size_t);
698
errnop = va_arg(ap, int *);
699
700
*errnop = nis_getstate(&st);
701
if (*errnop != 0)
702
return (NS_UNAVAIL);
703
704
if (st->yp_domain[0] == '\0') {
705
if (getdomainname(st->yp_domain, sizeof st->yp_domain)) {
706
*errnop = errno;
707
return (NS_UNAVAIL);
708
}
709
}
710
711
do {
712
switch (how) {
713
case nss_lt_name:
714
free(buf);
715
asprintf(&buf, "%s/%s", name, proto);
716
if (buf == NULL)
717
return (NS_TRYAGAIN);
718
if (yp_match(st->yp_domain, "services.byname", buf,
719
strlen(buf), &resultbuf, &resultbuflen)) {
720
rv = NS_NOTFOUND;
721
goto fin;
722
}
723
break;
724
case nss_lt_id:
725
free(buf);
726
asprintf(&buf, "%d/%s", ntohs(port), proto);
727
if (buf == NULL)
728
return (NS_TRYAGAIN);
729
730
/*
731
* We have to be a little flexible
732
* here. Ideally you're supposed to have both
733
* a services.byname and a services.byport
734
* map, but some systems have only
735
* services.byname. FreeBSD cheats a little by
736
* putting the services.byport information in
737
* the same map as services.byname so that
738
* either case will work. We allow for both
739
* possibilities here: if there is no
740
* services.byport map, we try services.byname
741
* instead.
742
*/
743
rv = yp_match(st->yp_domain, "services.byport", buf,
744
strlen(buf), &resultbuf, &resultbuflen);
745
if (rv) {
746
if (rv == YPERR_MAP) {
747
if (yp_match(st->yp_domain,
748
"services.byname", buf,
749
strlen(buf), &resultbuf,
750
&resultbuflen)) {
751
rv = NS_NOTFOUND;
752
goto fin;
753
}
754
} else {
755
rv = NS_NOTFOUND;
756
goto fin;
757
}
758
}
759
760
break;
761
case nss_lt_all:
762
if (!st->yp_stepping) {
763
free(st->yp_key);
764
rv = yp_first(st->yp_domain, "services.byname",
765
&st->yp_key, &st->yp_keylen, &resultbuf,
766
&resultbuflen);
767
if (rv) {
768
rv = NS_NOTFOUND;
769
goto fin;
770
}
771
st->yp_stepping = 1;
772
} else {
773
lastkey = st->yp_key;
774
rv = yp_next(st->yp_domain, "services.byname",
775
st->yp_key, st->yp_keylen, &st->yp_key,
776
&st->yp_keylen, &resultbuf, &resultbuflen);
777
free(lastkey);
778
if (rv) {
779
st->yp_stepping = 0;
780
rv = NS_NOTFOUND;
781
goto fin;
782
}
783
}
784
break;
785
}
786
787
rv = parse_result(serv, buffer, bufsize, resultbuf,
788
resultbuflen, errnop);
789
free(resultbuf);
790
791
} while (!(rv & NS_TERMINATE) && how == nss_lt_all);
792
793
fin:
794
free(buf);
795
if (rv == NS_SUCCESS && retval != NULL)
796
*(struct servent **)retval = serv;
797
798
return (rv);
799
}
800
801
static int
802
nis_setservent(void *result, void *mdata, va_list ap)
803
{
804
struct nis_state *st;
805
int rv;
806
807
rv = nis_getstate(&st);
808
if (rv != 0)
809
return (NS_UNAVAIL);
810
811
switch ((enum constants)(uintptr_t)mdata) {
812
case SETSERVENT:
813
case ENDSERVENT:
814
free(st->yp_key);
815
st->yp_key = NULL;
816
st->yp_stepping = 0;
817
break;
818
default:
819
break;
820
}
821
822
return (NS_UNAVAIL);
823
}
824
#endif
825
826
/* compat backend implementation */
827
static int
828
compat_setservent(void *retval, void *mdata, va_list ap)
829
{
830
static const ns_src compat_src[] = {
831
#ifdef YP
832
{ NSSRC_NIS, NS_SUCCESS },
833
#endif
834
{ NULL, 0 }
835
};
836
ns_dtab compat_dtab[] = {
837
{ NSSRC_DB, db_setservent, mdata },
838
#ifdef YP
839
{ NSSRC_NIS, nis_setservent, mdata },
840
#endif
841
{ NULL, NULL, NULL }
842
};
843
int f;
844
845
(void)files_setservent(retval, mdata, ap);
846
847
switch ((enum constants)(uintptr_t)mdata) {
848
case SETSERVENT:
849
f = va_arg(ap,int);
850
(void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
851
"setservent", compat_src, f);
852
break;
853
case ENDSERVENT:
854
(void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
855
"endservent", compat_src);
856
break;
857
default:
858
break;
859
}
860
861
return (NS_UNAVAIL);
862
}
863
864
#ifdef NS_CACHING
865
static int
866
serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
867
{
868
char *name;
869
char *proto;
870
int port;
871
872
size_t desired_size, size, size2;
873
enum nss_lookup_type lookup_type;
874
int res = NS_UNAVAIL;
875
876
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
877
switch (lookup_type) {
878
case nss_lt_name:
879
name = va_arg(ap, char *);
880
proto = va_arg(ap, char *);
881
882
size = strlen(name);
883
desired_size = sizeof(enum nss_lookup_type) + size + 1;
884
if (proto != NULL) {
885
size2 = strlen(proto);
886
desired_size += size2 + 1;
887
} else
888
size2 = 0;
889
890
if (desired_size > *buffer_size) {
891
res = NS_RETURN;
892
goto fin;
893
}
894
895
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
896
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
897
898
if (proto != NULL)
899
memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1,
900
proto, size2 + 1);
901
902
res = NS_SUCCESS;
903
break;
904
case nss_lt_id:
905
port = va_arg(ap, int);
906
proto = va_arg(ap, char *);
907
908
desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
909
if (proto != NULL) {
910
size = strlen(proto);
911
desired_size += size + 1;
912
} else
913
size = 0;
914
915
if (desired_size > *buffer_size) {
916
res = NS_RETURN;
917
goto fin;
918
}
919
920
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
921
memcpy(buffer + sizeof(enum nss_lookup_type), &port,
922
sizeof(int));
923
924
if (proto != NULL)
925
memcpy(buffer + sizeof(enum nss_lookup_type) +
926
sizeof(int), proto, size + 1);
927
928
res = NS_SUCCESS;
929
break;
930
default:
931
/* should be unreachable */
932
return (NS_UNAVAIL);
933
}
934
935
fin:
936
*buffer_size = desired_size;
937
return (res);
938
}
939
940
static int
941
serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
942
void *cache_mdata)
943
{
944
char *name __unused;
945
char *proto __unused;
946
int port __unused;
947
struct servent *serv;
948
char *orig_buf __unused;
949
size_t orig_buf_size __unused;
950
951
struct servent new_serv;
952
size_t desired_size;
953
char **alias;
954
char *p;
955
size_t size;
956
size_t aliases_size;
957
958
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
959
case nss_lt_name:
960
name = va_arg(ap, char *);
961
proto = va_arg(ap, char *);
962
break;
963
case nss_lt_id:
964
port = va_arg(ap, int);
965
proto = va_arg(ap, char *);
966
break;
967
case nss_lt_all:
968
break;
969
default:
970
/* should be unreachable */
971
return (NS_UNAVAIL);
972
}
973
974
serv = va_arg(ap, struct servent *);
975
orig_buf = va_arg(ap, char *);
976
orig_buf_size = va_arg(ap, size_t);
977
978
desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *);
979
if (serv->s_name != NULL)
980
desired_size += strlen(serv->s_name) + 1;
981
if (serv->s_proto != NULL)
982
desired_size += strlen(serv->s_proto) + 1;
983
984
aliases_size = 0;
985
if (serv->s_aliases != NULL) {
986
for (alias = serv->s_aliases; *alias; ++alias) {
987
desired_size += strlen(*alias) + 1;
988
++aliases_size;
989
}
990
991
desired_size += _ALIGNBYTES +
992
sizeof(char *) * (aliases_size + 1);
993
}
994
995
if (*buffer_size < desired_size) {
996
/* this assignment is here for future use */
997
*buffer_size = desired_size;
998
return (NS_RETURN);
999
}
1000
1001
memcpy(&new_serv, serv, sizeof(struct servent));
1002
memset(buffer, 0, desired_size);
1003
1004
*buffer_size = desired_size;
1005
p = buffer + sizeof(struct servent) + sizeof(char *);
1006
memcpy(buffer + sizeof(struct servent), &p, sizeof(char *));
1007
p = (char *)_ALIGN(p);
1008
1009
if (new_serv.s_name != NULL) {
1010
size = strlen(new_serv.s_name);
1011
memcpy(p, new_serv.s_name, size);
1012
new_serv.s_name = p;
1013
p += size + 1;
1014
}
1015
1016
if (new_serv.s_proto != NULL) {
1017
size = strlen(new_serv.s_proto);
1018
memcpy(p, new_serv.s_proto, size);
1019
new_serv.s_proto = p;
1020
p += size + 1;
1021
}
1022
1023
if (new_serv.s_aliases != NULL) {
1024
p = (char *)_ALIGN(p);
1025
memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size);
1026
new_serv.s_aliases = (char **)p;
1027
p += sizeof(char *) * (aliases_size + 1);
1028
1029
for (alias = new_serv.s_aliases; *alias; ++alias) {
1030
size = strlen(*alias);
1031
memcpy(p, *alias, size);
1032
*alias = p;
1033
p += size + 1;
1034
}
1035
}
1036
1037
memcpy(buffer, &new_serv, sizeof(struct servent));
1038
return (NS_SUCCESS);
1039
}
1040
1041
static int
1042
serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
1043
void *cache_mdata)
1044
{
1045
char *name __unused;
1046
char *proto __unused;
1047
int port __unused;
1048
struct servent *serv;
1049
char *orig_buf;
1050
char *p;
1051
char **alias;
1052
size_t orig_buf_size;
1053
int *ret_errno;
1054
1055
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
1056
case nss_lt_name:
1057
name = va_arg(ap, char *);
1058
proto = va_arg(ap, char *);
1059
break;
1060
case nss_lt_id:
1061
port = va_arg(ap, int);
1062
proto = va_arg(ap, char *);
1063
break;
1064
case nss_lt_all:
1065
break;
1066
default:
1067
/* should be unreachable */
1068
return (NS_UNAVAIL);
1069
}
1070
1071
serv = va_arg(ap, struct servent *);
1072
orig_buf = va_arg(ap, char *);
1073
orig_buf_size = va_arg(ap, size_t);
1074
ret_errno = va_arg(ap, int *);
1075
1076
if (orig_buf_size <
1077
buffer_size - sizeof(struct servent) - sizeof(char *)) {
1078
*ret_errno = ERANGE;
1079
return (NS_RETURN);
1080
}
1081
1082
memcpy(serv, buffer, sizeof(struct servent));
1083
memcpy(&p, buffer + sizeof(struct servent), sizeof(char *));
1084
1085
orig_buf = (char *)_ALIGN(orig_buf);
1086
memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) +
1087
(_ALIGN(p) - (size_t)p),
1088
buffer_size - sizeof(struct servent) - sizeof(char *) -
1089
(_ALIGN(p) - (size_t)p));
1090
p = (char *)_ALIGN(p);
1091
1092
NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *);
1093
NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *);
1094
if (serv->s_aliases != NULL) {
1095
NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **);
1096
1097
for (alias = serv->s_aliases; *alias; ++alias)
1098
NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
1099
}
1100
1101
if (retval != NULL)
1102
*((struct servent **)retval) = serv;
1103
return (NS_SUCCESS);
1104
}
1105
1106
NSS_MP_CACHE_HANDLING(services);
1107
#endif /* NS_CACHING */
1108
1109
/* get**_r functions implementation */
1110
int
1111
getservbyname_r(const char *name, const char *proto, struct servent *serv,
1112
char *buffer, size_t bufsize, struct servent **result)
1113
{
1114
static const struct servent_mdata mdata = { nss_lt_name, 0 };
1115
static const struct servent_mdata compat_mdata = { nss_lt_name, 1 };
1116
#ifdef NS_CACHING
1117
static const nss_cache_info cache_info =
1118
NS_COMMON_CACHE_INFO_INITIALIZER(
1119
services, (void *)nss_lt_name,
1120
serv_id_func, serv_marshal_func, serv_unmarshal_func);
1121
#endif /* NS_CACHING */
1122
static const ns_dtab dtab[] = {
1123
{ NSSRC_FILES, files_servent, (void *)&mdata },
1124
{ NSSRC_DB, db_servent, (void *)nss_lt_name },
1125
#ifdef YP
1126
{ NSSRC_NIS, nis_servent, (void *)nss_lt_name },
1127
#endif
1128
{ NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1129
#ifdef NS_CACHING
1130
NS_CACHE_CB(&cache_info)
1131
#endif
1132
{ NULL, NULL, NULL }
1133
};
1134
int rv, ret_errno;
1135
1136
ret_errno = 0;
1137
*result = NULL;
1138
rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r",
1139
defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno);
1140
1141
if (rv == NS_SUCCESS)
1142
return (0);
1143
else
1144
return (ret_errno);
1145
}
1146
1147
int
1148
getservbyport_r(int port, const char *proto, struct servent *serv,
1149
char *buffer, size_t bufsize, struct servent **result)
1150
{
1151
static const struct servent_mdata mdata = { nss_lt_id, 0 };
1152
static const struct servent_mdata compat_mdata = { nss_lt_id, 1 };
1153
#ifdef NS_CACHING
1154
static const nss_cache_info cache_info =
1155
NS_COMMON_CACHE_INFO_INITIALIZER(
1156
services, (void *)nss_lt_id,
1157
serv_id_func, serv_marshal_func, serv_unmarshal_func);
1158
#endif
1159
static const ns_dtab dtab[] = {
1160
{ NSSRC_FILES, files_servent, (void *)&mdata },
1161
{ NSSRC_DB, db_servent, (void *)nss_lt_id },
1162
#ifdef YP
1163
{ NSSRC_NIS, nis_servent, (void *)nss_lt_id },
1164
#endif
1165
{ NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1166
#ifdef NS_CACHING
1167
NS_CACHE_CB(&cache_info)
1168
#endif
1169
{ NULL, NULL, NULL }
1170
};
1171
int rv, ret_errno;
1172
1173
ret_errno = 0;
1174
*result = NULL;
1175
rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r",
1176
defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno);
1177
1178
if (rv == NS_SUCCESS)
1179
return (0);
1180
else
1181
return (ret_errno);
1182
}
1183
1184
int
1185
getservent_r(struct servent *serv, char *buffer, size_t bufsize,
1186
struct servent **result)
1187
{
1188
static const struct servent_mdata mdata = { nss_lt_all, 0 };
1189
static const struct servent_mdata compat_mdata = { nss_lt_all, 1 };
1190
#ifdef NS_CACHING
1191
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1192
services, (void *)nss_lt_all,
1193
serv_marshal_func, serv_unmarshal_func);
1194
#endif
1195
static const ns_dtab dtab[] = {
1196
{ NSSRC_FILES, files_servent, (void *)&mdata },
1197
{ NSSRC_DB, db_servent, (void *)nss_lt_all },
1198
#ifdef YP
1199
{ NSSRC_NIS, nis_servent, (void *)nss_lt_all },
1200
#endif
1201
{ NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
1202
#ifdef NS_CACHING
1203
NS_CACHE_CB(&cache_info)
1204
#endif
1205
{ NULL, NULL, NULL }
1206
};
1207
int rv, ret_errno;
1208
1209
ret_errno = 0;
1210
*result = NULL;
1211
rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r",
1212
defaultsrc, serv, buffer, bufsize, &ret_errno);
1213
1214
if (rv == NS_SUCCESS)
1215
return (0);
1216
else
1217
return (ret_errno);
1218
}
1219
1220
void
1221
setservent(int stayopen)
1222
{
1223
#ifdef NS_CACHING
1224
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1225
services, (void *)nss_lt_all,
1226
NULL, NULL);
1227
#endif
1228
static const ns_dtab dtab[] = {
1229
{ NSSRC_FILES, files_setservent, (void *)SETSERVENT },
1230
{ NSSRC_DB, db_setservent, (void *)SETSERVENT },
1231
#ifdef YP
1232
{ NSSRC_NIS, nis_setservent, (void *)SETSERVENT },
1233
#endif
1234
{ NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT },
1235
#ifdef NS_CACHING
1236
NS_CACHE_CB(&cache_info)
1237
#endif
1238
{ NULL, NULL, NULL }
1239
};
1240
1241
(void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc,
1242
stayopen);
1243
}
1244
1245
void
1246
endservent(void)
1247
{
1248
#ifdef NS_CACHING
1249
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1250
services, (void *)nss_lt_all,
1251
NULL, NULL);
1252
#endif
1253
static const ns_dtab dtab[] = {
1254
{ NSSRC_FILES, files_setservent, (void *)ENDSERVENT },
1255
{ NSSRC_DB, db_setservent, (void *)ENDSERVENT },
1256
#ifdef YP
1257
{ NSSRC_NIS, nis_setservent, (void *)ENDSERVENT },
1258
#endif
1259
{ NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT },
1260
#ifdef NS_CACHING
1261
NS_CACHE_CB(&cache_info)
1262
#endif
1263
{ NULL, NULL, NULL }
1264
};
1265
1266
(void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc);
1267
}
1268
1269
/* get** wrappers for get**_r functions implementation */
1270
static void
1271
servent_endstate(void *p)
1272
{
1273
if (p == NULL)
1274
return;
1275
1276
free(((struct servent_state *)p)->buffer);
1277
free(p);
1278
}
1279
1280
static int
1281
wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer,
1282
size_t bufsize, struct servent **res)
1283
{
1284
return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize,
1285
res));
1286
}
1287
1288
static int
1289
wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer,
1290
size_t bufsize, struct servent **res)
1291
{
1292
return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize,
1293
res));
1294
}
1295
1296
static int
1297
wrap_getservent_r(struct key key, struct servent *serv, char *buffer,
1298
size_t bufsize, struct servent **res)
1299
{
1300
return (getservent_r(serv, buffer, bufsize, res));
1301
}
1302
1303
static struct servent *
1304
getserv(int (*fn)(struct key, struct servent *, char *, size_t,
1305
struct servent **), struct key key)
1306
{
1307
int rv;
1308
struct servent *res;
1309
struct servent_state * st;
1310
1311
rv = servent_getstate(&st);
1312
if (rv != 0) {
1313
errno = rv;
1314
return NULL;
1315
}
1316
1317
if (st->buffer == NULL) {
1318
st->buffer = malloc(SERVENT_STORAGE_INITIAL);
1319
if (st->buffer == NULL)
1320
return (NULL);
1321
st->bufsize = SERVENT_STORAGE_INITIAL;
1322
}
1323
do {
1324
rv = fn(key, &st->serv, st->buffer, st->bufsize, &res);
1325
if (res == NULL && rv == ERANGE) {
1326
free(st->buffer);
1327
if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) {
1328
st->buffer = NULL;
1329
errno = ERANGE;
1330
return (NULL);
1331
}
1332
st->bufsize <<= 1;
1333
st->buffer = malloc(st->bufsize);
1334
if (st->buffer == NULL)
1335
return (NULL);
1336
}
1337
} while (res == NULL && rv == ERANGE);
1338
if (rv != 0)
1339
errno = rv;
1340
1341
return (res);
1342
}
1343
1344
struct servent *
1345
getservbyname(const char *name, const char *proto)
1346
{
1347
struct key key;
1348
1349
key.name = name;
1350
key.proto = proto;
1351
1352
return (getserv(wrap_getservbyname_r, key));
1353
}
1354
1355
struct servent *
1356
getservbyport(int port, const char *proto)
1357
{
1358
struct key key;
1359
1360
key.port = port;
1361
key.proto = proto;
1362
1363
return (getserv(wrap_getservbyport_r, key));
1364
}
1365
1366
struct servent *
1367
getservent(void)
1368
{
1369
struct key key;
1370
1371
key.proto = NULL;
1372
key.port = 0;
1373
1374
return (getserv(wrap_getservent_r, key));
1375
}
1376
1377