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