xref: /freebsd/lib/libc/rpc/getrpcent.c (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
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)
34 static 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 */
72 enum 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 
80 static 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 */
89 struct files_state {
90 	FILE	*fp;
91 	int	stayopen;
92 };
93 
94 static	int	files_rpcent(void *, void *, va_list);
95 static	int	files_setrpcent(void *, void *, va_list);
96 
97 static	void	files_endstate(void *);
98 NSS_TLS_HANDLING(files);
99 
100 /* nis backend declarations */
101 #ifdef YP
102 struct nis_state {
103 	char	domain[MAXHOSTNAMELEN];
104 	char	*current;
105 	int	currentlen;
106 	int	stepping;
107 	int	no_name_map;
108 };
109 
110 static	int	nis_rpcent(void *, void *, va_list);
111 static	int	nis_setrpcent(void *, void *, va_list);
112 
113 static	void	nis_endstate(void *);
114 NSS_TLS_HANDLING(nis);
115 #endif
116 
117 /* get** wrappers for get**_r functions declarations */
118 struct rpcent_state {
119 	struct rpcent	rpc;
120 	char		*buffer;
121 	size_t	bufsize;
122 };
123 static	void	rpcent_endstate(void *);
124 NSS_TLS_HANDLING(rpcent);
125 
126 union key {
127 	const char	*name;
128 	int		number;
129 };
130 
131 static int wrap_getrpcbyname_r(union key, struct rpcent *, char *,
132 			size_t, struct rpcent **);
133 static int wrap_getrpcbynumber_r(union key, struct rpcent *, char *,
134 			size_t, struct rpcent **);
135 static int wrap_getrpcent_r(union key, struct rpcent *, char *,
136 			size_t, struct rpcent **);
137 static struct rpcent *getrpc(int (*fn)(union key, struct rpcent *, char *,
138 			size_t, struct rpcent **), union key);
139 
140 #ifdef NS_CACHING
141 static int rpc_id_func(char *, size_t *, va_list, void *);
142 static int rpc_marshal_func(char *, size_t *, void *, va_list, void *);
143 static int rpc_unmarshal_func(char *, size_t, void *, va_list, void *);
144 #endif
145 
146 static int
147 rpcent_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 */
194 static	void
195 files_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 
209 static int
210 files_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;
314 done:
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 
339 static int
340 files_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
376 static 	void
377 nis_endstate(void *p)
378 {
379 	if (p == NULL)
380 		return;
381 
382 	free(((struct nis_state *)p)->current);
383 	free(p);
384 }
385 
386 static int
387 nis_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;
561 done:
562 				rv = NS_SUCCESS;
563 			} else
564 				rv = NS_SUCCESS;
565 		}
566 
567 	} while (!(rv & NS_TERMINATE) && (how == nss_lt_all));
568 
569 fin:
570 	free(buf);
571 	if ((rv == NS_SUCCESS) && (retval != NULL))
572 		*((struct rpcent **)retval) = rpc;
573 
574 	return (rv);
575 }
576 
577 static int
578 nis_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
604 static int
605 rpc_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 
651 fin:
652 	*buffer_size = desired_size;
653 	return (res);
654 }
655 
656 static int
657 rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
658     void *cache_mdata)
659 {
660 	char *name __unused;
661 	int num __unused;
662 	struct rpcent *rpc;
663 	char *orig_buf __unused;
664 	size_t orig_buf_size __unused;
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 
743 static int
744 rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
745     void *cache_mdata)
746 {
747 	char *name __unused;
748 	int num __unused;
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 
806 NSS_MP_CACHE_HANDLING(rpc);
807 #endif /* NS_CACHING */
808 
809 
810 /* get**_r functions implementation */
811 static int
812 getrpcbyname_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 
844 static int
845 getrpcbynumber_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 
877 static int
878 getrpcent_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 */
910 static 	void
911 rpcent_endstate(void *p)
912 {
913 	if (p == NULL)
914 		return;
915 
916 	free(((struct rpcent_state *)p)->buffer);
917 	free(p);
918 }
919 
920 static	int
921 wrap_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 
927 static	int
928 wrap_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 
934 static	int
935 wrap_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 
941 static struct rpcent *
942 getrpc(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 
982 struct rpcent *
983 getrpcbyname(const char *name)
984 {
985 	union key key;
986 
987 	key.name = name;
988 
989 	return (getrpc(wrap_getrpcbyname_r, key));
990 }
991 
992 struct rpcent *
993 getrpcbynumber(int number)
994 {
995 	union key key;
996 
997 	key.number = number;
998 
999 	return (getrpc(wrap_getrpcbynumber_r, key));
1000 }
1001 
1002 struct rpcent *
1003 getrpcent(void)
1004 {
1005 	union key key;
1006 
1007 	key.number = 0;	/* not used */
1008 
1009 	return (getrpc(wrap_getrpcent_r, key));
1010 }
1011 
1012 void
1013 setrpcent(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 
1036 void
1037 endrpcent(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