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