1/*	$NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $	*/
2
3/*-
4 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * 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 are met:
9 * - Redistributions of source code must retain the above copyright notice,
10 *   this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 *   this list of conditions and the following disclaimer in the documentation
13 *   and/or other materials provided with the distribution.
14 * - Neither the name of Sun Microsystems, Inc. nor the names of its
15 *   contributors may be used to endorse or promote products derived
16 *   from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#if defined(LIBC_SCCS) && !defined(lint)
32static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro";
33#endif
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD$");
36
37/*
38 * Copyright (c) 1984 by Sun Microsystems, Inc.
39 */
40
41#include <sys/param.h>
42#include <sys/socket.h>
43#include <arpa/inet.h>
44#include <assert.h>
45#include <errno.h>
46#include <nsswitch.h>
47#include <netinet/in.h>
48#include <stdio.h>
49#include <string.h>
50#include <stdarg.h>
51#include <stdlib.h>
52#include <rpc/rpc.h>
53#ifdef YP
54#include <rpcsvc/yp_prot.h>
55#include <rpcsvc/ypclnt.h>
56#endif
57#include <unistd.h>
58#include "namespace.h"
59#include "reentrant.h"
60#include "un-namespace.h"
61#include "libc_private.h"
62#include "nss_tls.h"
63#ifdef NS_CACHING
64#include "nscache.h"
65#endif
66
67#define	RPCDB	"/etc/rpc"
68
69/* nsswitch declarations */
70enum constants
71{
72	SETRPCENT = 1,
73	ENDRPCENT = 2,
74	RPCENT_STORAGE_INITIAL	= 1 << 10, /* 1 KByte */
75	RPCENT_STORAGE_MAX	= 1 << 20, /* 1 MByte */
76};
77
78static const ns_src defaultsrc[] = {
79	{ NSSRC_FILES, NS_SUCCESS },
80#ifdef YP
81	{ NSSRC_NIS, NS_SUCCESS },
82#endif
83	{ NULL, 0 }
84};
85
86/* files backend declarations */
87struct files_state {
88	FILE	*fp;
89	int	stayopen;
90};
91
92static	int	files_rpcent(void *, void *, va_list);
93static	int	files_setrpcent(void *, void *, va_list);
94
95static	void	files_endstate(void *);
96NSS_TLS_HANDLING(files);
97
98/* nis backend declarations */
99#ifdef YP
100struct nis_state {
101	char	domain[MAXHOSTNAMELEN];
102	char	*current;
103	int	currentlen;
104	int	stepping;
105	int	no_name_map;
106};
107
108static	int	nis_rpcent(void *, void *, va_list);
109static	int	nis_setrpcent(void *, void *, va_list);
110
111static	void	nis_endstate(void *);
112NSS_TLS_HANDLING(nis);
113#endif
114
115/* get** wrappers for get**_r functions declarations */
116struct rpcent_state {
117	struct rpcent	rpc;
118	char		*buffer;
119	size_t	bufsize;
120};
121static	void	rpcent_endstate(void *);
122NSS_TLS_HANDLING(rpcent);
123
124union key {
125	const char	*name;
126	int		number;
127};
128
129static int wrap_getrpcbyname_r(union key, struct rpcent *, char *,
130			size_t, struct rpcent **);
131static int wrap_getrpcbynumber_r(union key, struct rpcent *, char *,
132			size_t, struct rpcent **);
133static int wrap_getrpcent_r(union key, struct rpcent *, char *,
134			size_t, struct rpcent **);
135static struct rpcent *getrpc(int (*fn)(union key, struct rpcent *, char *,
136			size_t, struct rpcent **), union key);
137
138#ifdef NS_CACHING
139static int rpc_id_func(char *, size_t *, va_list, void *);
140static int rpc_marshal_func(char *, size_t *, void *, va_list, void *);
141static int rpc_unmarshal_func(char *, size_t, void *, va_list, void *);
142#endif
143
144static int
145rpcent_unpack(char *p, struct rpcent *rpc, char **r_aliases,
146	size_t aliases_size, int *errnop)
147{
148	char *cp, **q;
149
150	assert(p != NULL);
151
152	if (*p == '#')
153		return (-1);
154	cp = strpbrk(p, "#\n");
155	if (cp == NULL)
156		return (-1);
157	*cp = '\0';
158	cp = strpbrk(p, " \t");
159	if (cp == NULL)
160		return (-1);
161	*cp++ = '\0';
162	/* THIS STUFF IS INTERNET SPECIFIC */
163	rpc->r_name = p;
164	while (*cp == ' ' || *cp == '\t')
165		cp++;
166	rpc->r_number = atoi(cp);
167	q = rpc->r_aliases = r_aliases;
168	cp = strpbrk(cp, " \t");
169	if (cp != NULL)
170		*cp++ = '\0';
171	while (cp && *cp) {
172		if (*cp == ' ' || *cp == '\t') {
173			cp++;
174			continue;
175		}
176		if (q < &(r_aliases[aliases_size - 1]))
177			*q++ = cp;
178		else {
179			*errnop = ERANGE;
180			return -1;
181		}
182
183		cp = strpbrk(cp, " \t");
184		if (cp != NULL)
185			*cp++ = '\0';
186	}
187	*q = NULL;
188	return 0;
189}
190
191/* files backend implementation */
192static	void
193files_endstate(void *p)
194{
195	FILE * f;
196
197	if (p == NULL)
198		return;
199
200	f = ((struct files_state *)p)->fp;
201	if (f != NULL)
202		fclose(f);
203
204	free(p);
205}
206
207static int
208files_rpcent(void *retval, void *mdata, va_list ap)
209{
210	char *name;
211	int number;
212	struct rpcent *rpc;
213	char *buffer;
214	size_t bufsize;
215	int *errnop;
216
217	char *line;
218	size_t linesize;
219	char **aliases;
220	int aliases_size;
221	char **rp;
222
223	struct files_state	*st;
224	int rv;
225	int stayopen;
226	enum nss_lookup_type how;
227
228	how = (enum nss_lookup_type)mdata;
229	switch (how)
230	{
231	case nss_lt_name:
232		name = va_arg(ap, char *);
233		break;
234	case nss_lt_id:
235		number = va_arg(ap, int);
236		break;
237	case nss_lt_all:
238		break;
239	default:
240		return (NS_NOTFOUND);
241	}
242
243	rpc = va_arg(ap, struct rpcent *);
244	buffer = va_arg(ap, char *);
245	bufsize = va_arg(ap, size_t);
246	errnop = va_arg(ap, int *);
247
248	*errnop = files_getstate(&st);
249	if (*errnop != 0)
250		return (NS_UNAVAIL);
251
252	if (st->fp == NULL && (st->fp = fopen(RPCDB, "r")) == NULL) {
253		*errnop = errno;
254		return (NS_UNAVAIL);
255	}
256
257	if (how == nss_lt_all)
258		stayopen = 1;
259	else {
260		rewind(st->fp);
261		stayopen = st->stayopen;
262	}
263
264	do {
265		if ((line = fgetln(st->fp, &linesize)) == NULL) {
266			*errnop = errno;
267			rv = NS_RETURN;
268			break;
269		}
270
271		if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
272			*errnop = ERANGE;
273			rv = NS_RETURN;
274			break;
275		}
276
277		aliases = (char **)_ALIGN(&buffer[linesize+1]);
278		aliases_size = (buffer + bufsize -
279			(char *)aliases)/sizeof(char *);
280		if (aliases_size < 1) {
281			*errnop = ERANGE;
282			rv = NS_RETURN;
283			break;
284		}
285
286		memcpy(buffer, line, linesize);
287		buffer[linesize] = '\0';
288
289		rv = rpcent_unpack(buffer, rpc, aliases, aliases_size, errnop);
290		if (rv != 0) {
291			if (*errnop == 0) {
292				rv = NS_NOTFOUND;
293				continue;
294			}
295			else {
296				rv = NS_RETURN;
297				break;
298			}
299		}
300
301		switch (how)
302		{
303		case nss_lt_name:
304			if (strcmp(rpc->r_name, name) == 0)
305				goto done;
306			for (rp = rpc->r_aliases; *rp != NULL; rp++) {
307				if (strcmp(*rp, name) == 0)
308					goto done;
309			}
310			rv = NS_NOTFOUND;
311			continue;
312done:
313			rv = NS_SUCCESS;
314			break;
315		case nss_lt_id:
316			rv = (rpc->r_number == number) ? NS_SUCCESS :
317				NS_NOTFOUND;
318			break;
319		case nss_lt_all:
320			rv = NS_SUCCESS;
321			break;
322		}
323
324	} while (!(rv & NS_TERMINATE));
325
326	if (!stayopen && st->fp!=NULL) {
327		fclose(st->fp);
328		st->fp = NULL;
329	}
330
331	if ((rv == NS_SUCCESS) && (retval != NULL))
332		*((struct rpcent **)retval) = rpc;
333
334	return (rv);
335}
336
337static int
338files_setrpcent(void *retval, void *mdata, va_list ap)
339{
340	struct files_state	*st;
341	int	rv;
342	int	f;
343
344	rv = files_getstate(&st);
345	if (rv != 0)
346		return (NS_UNAVAIL);
347
348	switch ((enum constants)mdata)
349	{
350	case SETRPCENT:
351		f = va_arg(ap,int);
352		if (st->fp == NULL)
353			st->fp = fopen(RPCDB, "r");
354		else
355			rewind(st->fp);
356		st->stayopen |= f;
357		break;
358	case ENDRPCENT:
359		if (st->fp != NULL) {
360			fclose(st->fp);
361			st->fp = NULL;
362		}
363		st->stayopen = 0;
364		break;
365	default:
366		break;
367	}
368
369	return (NS_UNAVAIL);
370}
371
372/* nis backend implementation */
373#ifdef YP
374static 	void
375nis_endstate(void *p)
376{
377	if (p == NULL)
378		return;
379
380	free(((struct nis_state *)p)->current);
381	free(p);
382}
383
384static int
385nis_rpcent(void *retval, void *mdata, va_list ap)
386{
387	char		*name;
388	int		number;
389	struct rpcent	*rpc;
390	char		*buffer;
391	size_t	bufsize;
392	int		*errnop;
393
394	char		**rp;
395	char		**aliases;
396	int		aliases_size;
397
398	char	*lastkey;
399	char	*resultbuf;
400	int	resultbuflen;
401	char	buf[YPMAXRECORD + 2];
402
403	struct nis_state	*st;
404	int		rv;
405	enum nss_lookup_type	how;
406	int	no_name_active;
407
408	how = (enum nss_lookup_type)mdata;
409	switch (how)
410	{
411	case nss_lt_name:
412		name = va_arg(ap, char *);
413		break;
414	case nss_lt_id:
415		number = va_arg(ap, int);
416		break;
417	case nss_lt_all:
418		break;
419	default:
420		return (NS_NOTFOUND);
421	}
422
423	rpc = va_arg(ap, struct rpcent *);
424	buffer = va_arg(ap, char *);
425	bufsize = va_arg(ap, size_t);
426	errnop = va_arg(ap, int *);
427
428	*errnop = nis_getstate(&st);
429	if (*errnop != 0)
430		return (NS_UNAVAIL);
431
432	if (st->domain[0] == '\0') {
433		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
434			*errnop = errno;
435			return (NS_UNAVAIL);
436		}
437	}
438
439	no_name_active = 0;
440	do {
441		switch (how)
442		{
443		case nss_lt_name:
444			if (!st->no_name_map)
445			{
446				snprintf(buf, sizeof buf, "%s", name);
447				rv = yp_match(st->domain, "rpc.byname", buf,
448			    		strlen(buf), &resultbuf, &resultbuflen);
449
450				switch (rv) {
451				case 0:
452					break;
453				case YPERR_MAP:
454					st->stepping = 0;
455					no_name_active = 1;
456					how = nss_lt_all;
457
458					rv = NS_NOTFOUND;
459					continue;
460				default:
461					rv = NS_NOTFOUND;
462					goto fin;
463				}
464			} else {
465				st->stepping = 0;
466				no_name_active = 1;
467				how = nss_lt_all;
468
469				rv = NS_NOTFOUND;
470				continue;
471			}
472		break;
473		case nss_lt_id:
474			snprintf(buf, sizeof buf, "%d", number);
475			if (yp_match(st->domain, "rpc.bynumber", buf,
476			    	strlen(buf), &resultbuf, &resultbuflen)) {
477				rv = NS_NOTFOUND;
478				goto fin;
479			}
480			break;
481		case nss_lt_all:
482				if (!st->stepping) {
483					rv = yp_first(st->domain, "rpc.bynumber",
484				    		&st->current,
485						&st->currentlen, &resultbuf,
486				    		&resultbuflen);
487					if (rv) {
488						rv = NS_NOTFOUND;
489						goto fin;
490					}
491					st->stepping = 1;
492				} else {
493					lastkey = st->current;
494					rv = yp_next(st->domain, "rpc.bynumber",
495				    		st->current,
496						st->currentlen, &st->current,
497				    		&st->currentlen,
498						&resultbuf,	&resultbuflen);
499					free(lastkey);
500					if (rv) {
501						st->stepping = 0;
502						rv = NS_NOTFOUND;
503						goto fin;
504					}
505				}
506			break;
507		}
508
509		/* we need a room for additional \n symbol */
510		if (bufsize <= resultbuflen + 1 + _ALIGNBYTES +
511		    sizeof(char *)) {
512			*errnop = ERANGE;
513			rv = NS_RETURN;
514			free(resultbuf);
515			break;
516		}
517
518		aliases=(char **)_ALIGN(&buffer[resultbuflen+2]);
519		aliases_size = (buffer + bufsize - (char *)aliases) /
520			sizeof(char *);
521		if (aliases_size < 1) {
522			*errnop = ERANGE;
523			rv = NS_RETURN;
524			free(resultbuf);
525			break;
526		}
527
528		/*
529		 * rpcent_unpack expects lines terminated with \n -- make it happy
530		 */
531		memcpy(buffer, resultbuf, resultbuflen);
532		buffer[resultbuflen] = '\n';
533		buffer[resultbuflen+1] = '\0';
534		free(resultbuf);
535
536		if (rpcent_unpack(buffer, rpc, aliases, aliases_size,
537		    errnop) != 0) {
538			if (*errnop == 0)
539				rv = NS_NOTFOUND;
540			else
541				rv = NS_RETURN;
542		} else {
543			if ((how == nss_lt_all) && (no_name_active != 0)) {
544				if (strcmp(rpc->r_name, name) == 0)
545					goto done;
546				for (rp = rpc->r_aliases; *rp != NULL; rp++) {
547					if (strcmp(*rp, name) == 0)
548						goto done;
549				}
550				rv = NS_NOTFOUND;
551				continue;
552done:
553				rv = NS_SUCCESS;
554			} else
555				rv = NS_SUCCESS;
556		}
557
558	} while (!(rv & NS_TERMINATE) && (how == nss_lt_all));
559
560fin:
561	if ((rv == NS_SUCCESS) && (retval != NULL))
562		*((struct rpcent **)retval) = rpc;
563
564	return (rv);
565}
566
567static int
568nis_setrpcent(void *retval, void *mdata, va_list ap)
569{
570	struct nis_state	*st;
571	int	rv;
572
573	rv = nis_getstate(&st);
574	if (rv != 0)
575		return (NS_UNAVAIL);
576
577	switch ((enum constants)mdata)
578	{
579	case SETRPCENT:
580	case ENDRPCENT:
581		free(st->current);
582		st->current = NULL;
583		st->stepping = 0;
584		break;
585	default:
586		break;
587	}
588
589	return (NS_UNAVAIL);
590}
591#endif
592
593#ifdef NS_CACHING
594static int
595rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
596{
597	char *name;
598	int rpc;
599
600	size_t desired_size, size;
601	enum nss_lookup_type lookup_type;
602	int res = NS_UNAVAIL;
603
604	lookup_type = (enum nss_lookup_type)cache_mdata;
605	switch (lookup_type) {
606	case nss_lt_name:
607		name = va_arg(ap, char *);
608
609		size = strlen(name);
610		desired_size = sizeof(enum nss_lookup_type) + size + 1;
611		if (desired_size > *buffer_size) {
612			res = NS_RETURN;
613			goto fin;
614		}
615
616		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
617		memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
618
619		res = NS_SUCCESS;
620		break;
621	case nss_lt_id:
622		rpc = va_arg(ap, int);
623
624		desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
625		if (desired_size > *buffer_size) {
626			res = NS_RETURN;
627			goto fin;
628		}
629
630		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
631		memcpy(buffer + sizeof(enum nss_lookup_type), &rpc,
632		    sizeof(int));
633
634		res = NS_SUCCESS;
635		break;
636	default:
637		/* should be unreachable */
638		return (NS_UNAVAIL);
639	}
640
641fin:
642	*buffer_size = desired_size;
643	return (res);
644}
645
646static int
647rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
648    void *cache_mdata)
649{
650	char *name;
651	int num;
652	struct rpcent *rpc;
653	char *orig_buf;
654	size_t orig_buf_size;
655
656	struct rpcent new_rpc;
657	size_t desired_size, size, aliases_size;
658	char *p;
659	char **alias;
660
661	switch ((enum nss_lookup_type)cache_mdata) {
662	case nss_lt_name:
663		name = va_arg(ap, char *);
664		break;
665	case nss_lt_id:
666		num = va_arg(ap, int);
667		break;
668	case nss_lt_all:
669		break;
670	default:
671		/* should be unreachable */
672		return (NS_UNAVAIL);
673	}
674
675	rpc = va_arg(ap, struct rpcent *);
676	orig_buf = va_arg(ap, char *);
677	orig_buf_size = va_arg(ap, size_t);
678
679	desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *);
680	if (rpc->r_name != NULL)
681		desired_size += strlen(rpc->r_name) + 1;
682
683	if (rpc->r_aliases != NULL) {
684		aliases_size = 0;
685		for (alias = rpc->r_aliases; *alias; ++alias) {
686			desired_size += strlen(*alias) + 1;
687			++aliases_size;
688		}
689
690		desired_size += _ALIGNBYTES + (aliases_size + 1) *
691		    sizeof(char *);
692	}
693
694	if (*buffer_size < desired_size) {
695		/* this assignment is here for future use */
696		*buffer_size = desired_size;
697		return (NS_RETURN);
698	}
699
700	new_rpc = *rpc;
701
702	*buffer_size = desired_size;
703	memset(buffer, 0, desired_size);
704	p = buffer + sizeof(struct rpcent) + sizeof(char *);
705	memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *));
706	p = (char *)_ALIGN(p);
707
708	if (new_rpc.r_name != NULL) {
709		size = strlen(new_rpc.r_name);
710		memcpy(p, new_rpc.r_name, size);
711		new_rpc.r_name = p;
712		p += size + 1;
713	}
714
715	if (new_rpc.r_aliases != NULL) {
716		p = (char *)_ALIGN(p);
717		memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size);
718		new_rpc.r_aliases = (char **)p;
719		p += sizeof(char *) * (aliases_size + 1);
720
721		for (alias = new_rpc.r_aliases; *alias; ++alias) {
722			size = strlen(*alias);
723			memcpy(p, *alias, size);
724			*alias = p;
725			p += size + 1;
726		}
727	}
728
729	memcpy(buffer, &new_rpc, sizeof(struct rpcent));
730	return (NS_SUCCESS);
731}
732
733static int
734rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
735    void *cache_mdata)
736{
737	char *name;
738	int num;
739	struct rpcent *rpc;
740	char *orig_buf;
741	size_t orig_buf_size;
742	int *ret_errno;
743
744	char *p;
745	char **alias;
746
747	switch ((enum nss_lookup_type)cache_mdata) {
748	case nss_lt_name:
749		name = va_arg(ap, char *);
750		break;
751	case nss_lt_id:
752		num = va_arg(ap, int);
753		break;
754	case nss_lt_all:
755		break;
756	default:
757		/* should be unreachable */
758		return (NS_UNAVAIL);
759	}
760
761	rpc = va_arg(ap, struct rpcent *);
762	orig_buf = va_arg(ap, char *);
763	orig_buf_size = va_arg(ap, size_t);
764	ret_errno = va_arg(ap, int *);
765
766	if (orig_buf_size <
767	    buffer_size - sizeof(struct rpcent) - sizeof(char *)) {
768		*ret_errno = ERANGE;
769		return (NS_RETURN);
770	}
771
772	memcpy(rpc, buffer, sizeof(struct rpcent));
773	memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *));
774
775	orig_buf = (char *)_ALIGN(orig_buf);
776	memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) +
777	    _ALIGN(p) - (size_t)p,
778	    buffer_size - sizeof(struct rpcent) - sizeof(char *) -
779	    _ALIGN(p) + (size_t)p);
780	p = (char *)_ALIGN(p);
781
782	NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *);
783	if (rpc->r_aliases != NULL) {
784		NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **);
785
786		for (alias = rpc->r_aliases	; *alias; ++alias)
787			NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
788	}
789
790	if (retval != NULL)
791		*((struct rpcent **)retval) = rpc;
792
793	return (NS_SUCCESS);
794}
795
796NSS_MP_CACHE_HANDLING(rpc);
797#endif /* NS_CACHING */
798
799
800/* get**_r functions implementation */
801static int
802getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer,
803	size_t bufsize, struct rpcent **result)
804{
805#ifdef NS_CACHING
806	static const nss_cache_info cache_info =
807    		NS_COMMON_CACHE_INFO_INITIALIZER(
808		rpc, (void *)nss_lt_name,
809		rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
810#endif
811	static const ns_dtab dtab[] = {
812		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_name },
813#ifdef YP
814		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_name },
815#endif
816#ifdef NS_CACHING
817		NS_CACHE_CB(&cache_info)
818#endif
819		{ NULL, NULL, NULL }
820	};
821	int rv, ret_errno;
822
823	ret_errno = 0;
824	*result = NULL;
825	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc,
826	    name, rpc, buffer, bufsize, &ret_errno);
827
828	if (rv == NS_SUCCESS)
829		return (0);
830	else
831		return (ret_errno);
832}
833
834static int
835getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer,
836	size_t bufsize, struct rpcent **result)
837{
838#ifdef NS_CACHING
839	static const nss_cache_info cache_info =
840    		NS_COMMON_CACHE_INFO_INITIALIZER(
841		rpc, (void *)nss_lt_id,
842		rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
843#endif
844	static const ns_dtab dtab[] = {
845		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_id },
846#ifdef YP
847		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_id },
848#endif
849#ifdef NS_CACHING
850		NS_CACHE_CB(&cache_info)
851#endif
852		{ NULL, NULL, NULL }
853	};
854	int rv, ret_errno;
855
856	ret_errno = 0;
857	*result = NULL;
858	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc,
859	    number, rpc, buffer, bufsize, &ret_errno);
860
861	if (rv == NS_SUCCESS)
862		return (0);
863	else
864		return (ret_errno);
865}
866
867static int
868getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize,
869	struct rpcent **result)
870{
871#ifdef NS_CACHING
872	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
873		rpc, (void *)nss_lt_all,
874		rpc_marshal_func, rpc_unmarshal_func);
875#endif
876	static const ns_dtab dtab[] = {
877		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_all },
878#ifdef YP
879		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_all },
880#endif
881#ifdef NS_CACHING
882		NS_CACHE_CB(&cache_info)
883#endif
884		{ NULL, NULL, NULL }
885	};
886	int rv, ret_errno;
887
888	ret_errno = 0;
889	*result = NULL;
890	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc,
891	    rpc, buffer, bufsize, &ret_errno);
892
893	if (rv == NS_SUCCESS)
894		return (0);
895	else
896		return (ret_errno);
897}
898
899/* get** wrappers for get**_r functions implementation */
900static 	void
901rpcent_endstate(void *p)
902{
903	if (p == NULL)
904		return;
905
906	free(((struct rpcent_state *)p)->buffer);
907	free(p);
908}
909
910static	int
911wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer,
912    size_t bufsize, struct rpcent **res)
913{
914	return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res));
915}
916
917static	int
918wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer,
919    size_t bufsize, struct rpcent **res)
920{
921	return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res));
922}
923
924static	int
925wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer,
926    size_t bufsize, struct rpcent **res)
927{
928	return (getrpcent_r(rpc, buffer, bufsize, res));
929}
930
931static struct rpcent *
932getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **),
933    union key key)
934{
935	int		 rv;
936	struct rpcent	*res;
937	struct rpcent_state * st;
938
939	rv=rpcent_getstate(&st);
940	if (rv != 0) {
941		errno = rv;
942		return NULL;
943	}
944
945	if (st->buffer == NULL) {
946		st->buffer = malloc(RPCENT_STORAGE_INITIAL);
947		if (st->buffer == NULL)
948			return (NULL);
949		st->bufsize = RPCENT_STORAGE_INITIAL;
950	}
951	do {
952		rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res);
953		if (res == NULL && rv == ERANGE) {
954			free(st->buffer);
955			if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) {
956				st->buffer = NULL;
957				errno = ERANGE;
958				return (NULL);
959			}
960			st->bufsize <<= 1;
961			st->buffer = malloc(st->bufsize);
962			if (st->buffer == NULL)
963				return (NULL);
964		}
965	} while (res == NULL && rv == ERANGE);
966	if (rv != 0)
967		errno = rv;
968
969	return (res);
970}
971
972struct rpcent *
973getrpcbyname(const char *name)
974{
975	union key key;
976
977	key.name = name;
978
979	return (getrpc(wrap_getrpcbyname_r, key));
980}
981
982struct rpcent *
983getrpcbynumber(int number)
984{
985	union key key;
986
987	key.number = number;
988
989	return (getrpc(wrap_getrpcbynumber_r, key));
990}
991
992struct rpcent *
993getrpcent(void)
994{
995	union key key;
996
997	key.number = 0;	/* not used */
998
999	return (getrpc(wrap_getrpcent_r, key));
1000}
1001
1002void
1003setrpcent(int stayopen)
1004{
1005#ifdef NS_CACHING
1006	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1007		rpc, (void *)nss_lt_all,
1008		NULL, NULL);
1009#endif
1010
1011	static const ns_dtab dtab[] = {
1012		{ NSSRC_FILES, files_setrpcent, (void *)SETRPCENT },
1013#ifdef YP
1014		{ NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT },
1015#endif
1016#ifdef NS_CACHING
1017		NS_CACHE_CB(&cache_info)
1018#endif
1019		{ NULL, NULL, NULL }
1020	};
1021
1022	(void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc,
1023		stayopen);
1024}
1025
1026void
1027endrpcent(void)
1028{
1029#ifdef NS_CACHING
1030	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1031		rpc, (void *)nss_lt_all,
1032		NULL, NULL);
1033#endif
1034
1035	static const ns_dtab dtab[] = {
1036		{ NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT },
1037#ifdef YP
1038		{ NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT },
1039#endif
1040#ifdef NS_CACHING
1041		NS_CACHE_CB(&cache_info)
1042#endif
1043		{ NULL, NULL, NULL }
1044	};
1045
1046	(void)nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc);
1047}
1048