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