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