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