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