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