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