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$");
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)(uintptr_t)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)(uintptr_t)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;
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)(uintptr_t)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	buf = NULL;
426	rpc = va_arg(ap, struct rpcent *);
427	buffer = va_arg(ap, char *);
428	bufsize = va_arg(ap, size_t);
429	errnop = va_arg(ap, int *);
430
431	*errnop = nis_getstate(&st);
432	if (*errnop != 0)
433		return (NS_UNAVAIL);
434
435	if (st->domain[0] == '\0') {
436		if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
437			*errnop = errno;
438			return (NS_UNAVAIL);
439		}
440	}
441
442	no_name_active = 0;
443	do {
444		switch (how)
445		{
446		case nss_lt_name:
447			if (!st->no_name_map)
448			{
449				free(buf);
450				asprintf(&buf, "%s", name);
451				if (buf == NULL)
452					return (NS_TRYAGAIN);
453				rv = yp_match(st->domain, "rpc.byname", buf,
454			    		strlen(buf), &resultbuf, &resultbuflen);
455
456				switch (rv) {
457				case 0:
458					break;
459				case YPERR_MAP:
460					st->stepping = 0;
461					no_name_active = 1;
462					how = nss_lt_all;
463
464					rv = NS_NOTFOUND;
465					continue;
466				default:
467					rv = NS_NOTFOUND;
468					goto fin;
469				}
470			} else {
471				st->stepping = 0;
472				no_name_active = 1;
473				how = nss_lt_all;
474
475				rv = NS_NOTFOUND;
476				continue;
477			}
478		break;
479		case nss_lt_id:
480			free(buf);
481			asprintf(&buf, "%d", number);
482			if (buf == NULL)
483				return (NS_TRYAGAIN);
484			if (yp_match(st->domain, "rpc.bynumber", buf,
485			    	strlen(buf), &resultbuf, &resultbuflen)) {
486				rv = NS_NOTFOUND;
487				goto fin;
488			}
489			break;
490		case nss_lt_all:
491				if (!st->stepping) {
492					rv = yp_first(st->domain, "rpc.bynumber",
493				    		&st->current,
494						&st->currentlen, &resultbuf,
495				    		&resultbuflen);
496					if (rv) {
497						rv = NS_NOTFOUND;
498						goto fin;
499					}
500					st->stepping = 1;
501				} else {
502					lastkey = st->current;
503					rv = yp_next(st->domain, "rpc.bynumber",
504				    		st->current,
505						st->currentlen, &st->current,
506				    		&st->currentlen,
507						&resultbuf,	&resultbuflen);
508					free(lastkey);
509					if (rv) {
510						st->stepping = 0;
511						rv = NS_NOTFOUND;
512						goto fin;
513					}
514				}
515			break;
516		}
517
518		/* we need a room for additional \n symbol */
519		if (bufsize <= resultbuflen + 1 + _ALIGNBYTES +
520		    sizeof(char *)) {
521			*errnop = ERANGE;
522			rv = NS_RETURN;
523			free(resultbuf);
524			break;
525		}
526
527		aliases=(char **)_ALIGN(&buffer[resultbuflen+2]);
528		aliases_size = (buffer + bufsize - (char *)aliases) /
529			sizeof(char *);
530		if (aliases_size < 1) {
531			*errnop = ERANGE;
532			rv = NS_RETURN;
533			free(resultbuf);
534			break;
535		}
536
537		/*
538		 * rpcent_unpack expects lines terminated with \n -- make it happy
539		 */
540		memcpy(buffer, resultbuf, resultbuflen);
541		buffer[resultbuflen] = '\n';
542		buffer[resultbuflen+1] = '\0';
543		free(resultbuf);
544
545		if (rpcent_unpack(buffer, rpc, aliases, aliases_size,
546		    errnop) != 0) {
547			if (*errnop == 0)
548				rv = NS_NOTFOUND;
549			else
550				rv = NS_RETURN;
551		} else {
552			if ((how == nss_lt_all) && (no_name_active != 0)) {
553				if (strcmp(rpc->r_name, name) == 0)
554					goto done;
555				for (rp = rpc->r_aliases; *rp != NULL; rp++) {
556					if (strcmp(*rp, name) == 0)
557						goto done;
558				}
559				rv = NS_NOTFOUND;
560				continue;
561done:
562				rv = NS_SUCCESS;
563			} else
564				rv = NS_SUCCESS;
565		}
566
567	} while (!(rv & NS_TERMINATE) && (how == nss_lt_all));
568
569fin:
570	free(buf);
571	if ((rv == NS_SUCCESS) && (retval != NULL))
572		*((struct rpcent **)retval) = rpc;
573
574	return (rv);
575}
576
577static int
578nis_setrpcent(void *retval, void *mdata, va_list ap)
579{
580	struct nis_state	*st;
581	int	rv;
582
583	rv = nis_getstate(&st);
584	if (rv != 0)
585		return (NS_UNAVAIL);
586
587	switch ((enum constants)(uintptr_t)mdata)
588	{
589	case SETRPCENT:
590	case ENDRPCENT:
591		free(st->current);
592		st->current = NULL;
593		st->stepping = 0;
594		break;
595	default:
596		break;
597	}
598
599	return (NS_UNAVAIL);
600}
601#endif
602
603#ifdef NS_CACHING
604static int
605rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
606{
607	char *name;
608	int rpc;
609
610	size_t desired_size, size;
611	enum nss_lookup_type lookup_type;
612	int res = NS_UNAVAIL;
613
614	lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
615	switch (lookup_type) {
616	case nss_lt_name:
617		name = va_arg(ap, char *);
618
619		size = strlen(name);
620		desired_size = sizeof(enum nss_lookup_type) + size + 1;
621		if (desired_size > *buffer_size) {
622			res = NS_RETURN;
623			goto fin;
624		}
625
626		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
627		memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
628
629		res = NS_SUCCESS;
630		break;
631	case nss_lt_id:
632		rpc = va_arg(ap, int);
633
634		desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
635		if (desired_size > *buffer_size) {
636			res = NS_RETURN;
637			goto fin;
638		}
639
640		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
641		memcpy(buffer + sizeof(enum nss_lookup_type), &rpc,
642		    sizeof(int));
643
644		res = NS_SUCCESS;
645		break;
646	default:
647		/* should be unreachable */
648		return (NS_UNAVAIL);
649	}
650
651fin:
652	*buffer_size = desired_size;
653	return (res);
654}
655
656static int
657rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
658    void *cache_mdata)
659{
660	char *name;
661	int num;
662	struct rpcent *rpc;
663	char *orig_buf;
664	size_t orig_buf_size;
665
666	struct rpcent new_rpc;
667	size_t desired_size, size, aliases_size;
668	char *p;
669	char **alias;
670
671	switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
672	case nss_lt_name:
673		name = va_arg(ap, char *);
674		break;
675	case nss_lt_id:
676		num = va_arg(ap, int);
677		break;
678	case nss_lt_all:
679		break;
680	default:
681		/* should be unreachable */
682		return (NS_UNAVAIL);
683	}
684
685	rpc = va_arg(ap, struct rpcent *);
686	orig_buf = va_arg(ap, char *);
687	orig_buf_size = va_arg(ap, size_t);
688
689	desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *);
690	if (rpc->r_name != NULL)
691		desired_size += strlen(rpc->r_name) + 1;
692
693	if (rpc->r_aliases != NULL) {
694		aliases_size = 0;
695		for (alias = rpc->r_aliases; *alias; ++alias) {
696			desired_size += strlen(*alias) + 1;
697			++aliases_size;
698		}
699
700		desired_size += _ALIGNBYTES + (aliases_size + 1) *
701		    sizeof(char *);
702	}
703
704	if (*buffer_size < desired_size) {
705		/* this assignment is here for future use */
706		*buffer_size = desired_size;
707		return (NS_RETURN);
708	}
709
710	new_rpc = *rpc;
711
712	*buffer_size = desired_size;
713	memset(buffer, 0, desired_size);
714	p = buffer + sizeof(struct rpcent) + sizeof(char *);
715	memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *));
716	p = (char *)_ALIGN(p);
717
718	if (new_rpc.r_name != NULL) {
719		size = strlen(new_rpc.r_name);
720		memcpy(p, new_rpc.r_name, size);
721		new_rpc.r_name = p;
722		p += size + 1;
723	}
724
725	if (new_rpc.r_aliases != NULL) {
726		p = (char *)_ALIGN(p);
727		memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size);
728		new_rpc.r_aliases = (char **)p;
729		p += sizeof(char *) * (aliases_size + 1);
730
731		for (alias = new_rpc.r_aliases; *alias; ++alias) {
732			size = strlen(*alias);
733			memcpy(p, *alias, size);
734			*alias = p;
735			p += size + 1;
736		}
737	}
738
739	memcpy(buffer, &new_rpc, sizeof(struct rpcent));
740	return (NS_SUCCESS);
741}
742
743static int
744rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
745    void *cache_mdata)
746{
747	char *name;
748	int num;
749	struct rpcent *rpc;
750	char *orig_buf;
751	size_t orig_buf_size;
752	int *ret_errno;
753
754	char *p;
755	char **alias;
756
757	switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
758	case nss_lt_name:
759		name = va_arg(ap, char *);
760		break;
761	case nss_lt_id:
762		num = va_arg(ap, int);
763		break;
764	case nss_lt_all:
765		break;
766	default:
767		/* should be unreachable */
768		return (NS_UNAVAIL);
769	}
770
771	rpc = va_arg(ap, struct rpcent *);
772	orig_buf = va_arg(ap, char *);
773	orig_buf_size = va_arg(ap, size_t);
774	ret_errno = va_arg(ap, int *);
775
776	if (orig_buf_size <
777	    buffer_size - sizeof(struct rpcent) - sizeof(char *)) {
778		*ret_errno = ERANGE;
779		return (NS_RETURN);
780	}
781
782	memcpy(rpc, buffer, sizeof(struct rpcent));
783	memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *));
784
785	orig_buf = (char *)_ALIGN(orig_buf);
786	memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) +
787	    _ALIGN(p) - (size_t)p,
788	    buffer_size - sizeof(struct rpcent) - sizeof(char *) -
789	    _ALIGN(p) + (size_t)p);
790	p = (char *)_ALIGN(p);
791
792	NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *);
793	if (rpc->r_aliases != NULL) {
794		NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **);
795
796		for (alias = rpc->r_aliases	; *alias; ++alias)
797			NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
798	}
799
800	if (retval != NULL)
801		*((struct rpcent **)retval) = rpc;
802
803	return (NS_SUCCESS);
804}
805
806NSS_MP_CACHE_HANDLING(rpc);
807#endif /* NS_CACHING */
808
809
810/* get**_r functions implementation */
811static int
812getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer,
813	size_t bufsize, struct rpcent **result)
814{
815#ifdef NS_CACHING
816	static const nss_cache_info cache_info =
817    		NS_COMMON_CACHE_INFO_INITIALIZER(
818		rpc, (void *)nss_lt_name,
819		rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
820#endif
821	static const ns_dtab dtab[] = {
822		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_name },
823#ifdef YP
824		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_name },
825#endif
826#ifdef NS_CACHING
827		NS_CACHE_CB(&cache_info)
828#endif
829		{ NULL, NULL, NULL }
830	};
831	int rv, ret_errno;
832
833	ret_errno = 0;
834	*result = NULL;
835	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc,
836	    name, rpc, buffer, bufsize, &ret_errno);
837
838	if (rv == NS_SUCCESS)
839		return (0);
840	else
841		return (ret_errno);
842}
843
844static int
845getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer,
846	size_t bufsize, struct rpcent **result)
847{
848#ifdef NS_CACHING
849	static const nss_cache_info cache_info =
850    		NS_COMMON_CACHE_INFO_INITIALIZER(
851		rpc, (void *)nss_lt_id,
852		rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
853#endif
854	static const ns_dtab dtab[] = {
855		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_id },
856#ifdef YP
857		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_id },
858#endif
859#ifdef NS_CACHING
860		NS_CACHE_CB(&cache_info)
861#endif
862		{ NULL, NULL, NULL }
863	};
864	int rv, ret_errno;
865
866	ret_errno = 0;
867	*result = NULL;
868	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc,
869	    number, rpc, buffer, bufsize, &ret_errno);
870
871	if (rv == NS_SUCCESS)
872		return (0);
873	else
874		return (ret_errno);
875}
876
877static int
878getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize,
879	struct rpcent **result)
880{
881#ifdef NS_CACHING
882	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
883		rpc, (void *)nss_lt_all,
884		rpc_marshal_func, rpc_unmarshal_func);
885#endif
886	static const ns_dtab dtab[] = {
887		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_all },
888#ifdef YP
889		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_all },
890#endif
891#ifdef NS_CACHING
892		NS_CACHE_CB(&cache_info)
893#endif
894		{ NULL, NULL, NULL }
895	};
896	int rv, ret_errno;
897
898	ret_errno = 0;
899	*result = NULL;
900	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc,
901	    rpc, buffer, bufsize, &ret_errno);
902
903	if (rv == NS_SUCCESS)
904		return (0);
905	else
906		return (ret_errno);
907}
908
909/* get** wrappers for get**_r functions implementation */
910static 	void
911rpcent_endstate(void *p)
912{
913	if (p == NULL)
914		return;
915
916	free(((struct rpcent_state *)p)->buffer);
917	free(p);
918}
919
920static	int
921wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer,
922    size_t bufsize, struct rpcent **res)
923{
924	return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res));
925}
926
927static	int
928wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer,
929    size_t bufsize, struct rpcent **res)
930{
931	return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res));
932}
933
934static	int
935wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer,
936    size_t bufsize, struct rpcent **res)
937{
938	return (getrpcent_r(rpc, buffer, bufsize, res));
939}
940
941static struct rpcent *
942getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **),
943    union key key)
944{
945	int		 rv;
946	struct rpcent	*res;
947	struct rpcent_state * st;
948
949	rv=rpcent_getstate(&st);
950	if (rv != 0) {
951		errno = rv;
952		return NULL;
953	}
954
955	if (st->buffer == NULL) {
956		st->buffer = malloc(RPCENT_STORAGE_INITIAL);
957		if (st->buffer == NULL)
958			return (NULL);
959		st->bufsize = RPCENT_STORAGE_INITIAL;
960	}
961	do {
962		rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res);
963		if (res == NULL && rv == ERANGE) {
964			free(st->buffer);
965			if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) {
966				st->buffer = NULL;
967				errno = ERANGE;
968				return (NULL);
969			}
970			st->bufsize <<= 1;
971			st->buffer = malloc(st->bufsize);
972			if (st->buffer == NULL)
973				return (NULL);
974		}
975	} while (res == NULL && rv == ERANGE);
976	if (rv != 0)
977		errno = rv;
978
979	return (res);
980}
981
982struct rpcent *
983getrpcbyname(const char *name)
984{
985	union key key;
986
987	key.name = name;
988
989	return (getrpc(wrap_getrpcbyname_r, key));
990}
991
992struct rpcent *
993getrpcbynumber(int number)
994{
995	union key key;
996
997	key.number = number;
998
999	return (getrpc(wrap_getrpcbynumber_r, key));
1000}
1001
1002struct rpcent *
1003getrpcent(void)
1004{
1005	union key key;
1006
1007	key.number = 0;	/* not used */
1008
1009	return (getrpc(wrap_getrpcent_r, key));
1010}
1011
1012void
1013setrpcent(int stayopen)
1014{
1015#ifdef NS_CACHING
1016	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1017		rpc, (void *)nss_lt_all,
1018		NULL, NULL);
1019#endif
1020
1021	static const ns_dtab dtab[] = {
1022		{ NSSRC_FILES, files_setrpcent, (void *)SETRPCENT },
1023#ifdef YP
1024		{ NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT },
1025#endif
1026#ifdef NS_CACHING
1027		NS_CACHE_CB(&cache_info)
1028#endif
1029		{ NULL, NULL, NULL }
1030	};
1031
1032	(void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc,
1033		stayopen);
1034}
1035
1036void
1037endrpcent(void)
1038{
1039#ifdef NS_CACHING
1040	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1041		rpc, (void *)nss_lt_all,
1042		NULL, NULL);
1043#endif
1044
1045	static const ns_dtab dtab[] = {
1046		{ NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT },
1047#ifdef YP
1048		{ NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT },
1049#endif
1050#ifdef NS_CACHING
1051		NS_CACHE_CB(&cache_info)
1052#endif
1053		{ NULL, NULL, NULL }
1054	};
1055
1056	(void)nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc);
1057}
1058