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