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