xref: /freebsd/lib/libc/rpc/getrpcent.c (revision 8ef24a0d4b28fe230e20637f56869cc4148cd2ca)
1 /*	$NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009, Sun Microsystems, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  * - Redistributions of source code must retain the above copyright notice,
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Sun Microsystems, Inc. nor the names of its
15  *   contributors may be used to endorse or promote products derived
16  *   from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #if defined(LIBC_SCCS) && !defined(lint)
32 static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro";
33 #endif
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
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)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)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[YPMAXRECORD + 2];
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)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 	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 				snprintf(buf, sizeof buf, "%s", name);
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 			snprintf(buf, sizeof buf, "%d", number);
475 			if (yp_match(st->domain, "rpc.bynumber", buf,
476 			    	strlen(buf), &resultbuf, &resultbuflen)) {
477 				rv = NS_NOTFOUND;
478 				goto fin;
479 			}
480 			break;
481 		case nss_lt_all:
482 				if (!st->stepping) {
483 					rv = yp_first(st->domain, "rpc.bynumber",
484 				    		&st->current,
485 						&st->currentlen, &resultbuf,
486 				    		&resultbuflen);
487 					if (rv) {
488 						rv = NS_NOTFOUND;
489 						goto fin;
490 					}
491 					st->stepping = 1;
492 				} else {
493 					lastkey = st->current;
494 					rv = yp_next(st->domain, "rpc.bynumber",
495 				    		st->current,
496 						st->currentlen, &st->current,
497 				    		&st->currentlen,
498 						&resultbuf,	&resultbuflen);
499 					free(lastkey);
500 					if (rv) {
501 						st->stepping = 0;
502 						rv = NS_NOTFOUND;
503 						goto fin;
504 					}
505 				}
506 			break;
507 		}
508 
509 		/* we need a room for additional \n symbol */
510 		if (bufsize <= resultbuflen + 1 + _ALIGNBYTES +
511 		    sizeof(char *)) {
512 			*errnop = ERANGE;
513 			rv = NS_RETURN;
514 			break;
515 		}
516 
517 		aliases=(char **)_ALIGN(&buffer[resultbuflen+2]);
518 		aliases_size = (buffer + bufsize - (char *)aliases) /
519 			sizeof(char *);
520 		if (aliases_size < 1) {
521 			*errnop = ERANGE;
522 			rv = NS_RETURN;
523 			break;
524 		}
525 
526 		/*
527 		 * rpcent_unpack expects lines terminated with \n -- make it happy
528 		 */
529 		memcpy(buffer, resultbuf, resultbuflen);
530 		buffer[resultbuflen] = '\n';
531 		buffer[resultbuflen+1] = '\0';
532 		free(resultbuf);
533 
534 		if (rpcent_unpack(buffer, rpc, aliases, aliases_size,
535 		    errnop) != 0) {
536 			if (*errnop == 0)
537 				rv = NS_NOTFOUND;
538 			else
539 				rv = NS_RETURN;
540 		} else {
541 			if ((how == nss_lt_all) && (no_name_active != 0)) {
542 				if (strcmp(rpc->r_name, name) == 0)
543 					goto done;
544 				for (rp = rpc->r_aliases; *rp != NULL; rp++) {
545 					if (strcmp(*rp, name) == 0)
546 						goto done;
547 				}
548 				rv = NS_NOTFOUND;
549 				continue;
550 done:
551 				rv = NS_SUCCESS;
552 			} else
553 				rv = NS_SUCCESS;
554 		}
555 
556 	} while (!(rv & NS_TERMINATE) && (how == nss_lt_all));
557 
558 fin:
559 	if ((rv == NS_SUCCESS) && (retval != NULL))
560 		*((struct rpcent **)retval) = rpc;
561 
562 	return (rv);
563 }
564 
565 static int
566 nis_setrpcent(void *retval, void *mdata, va_list ap)
567 {
568 	struct nis_state	*st;
569 	int	rv;
570 
571 	rv = nis_getstate(&st);
572 	if (rv != 0)
573 		return (NS_UNAVAIL);
574 
575 	switch ((enum constants)mdata)
576 	{
577 	case SETRPCENT:
578 	case ENDRPCENT:
579 		free(st->current);
580 		st->current = NULL;
581 		st->stepping = 0;
582 		break;
583 	default:
584 		break;
585 	}
586 
587 	return (NS_UNAVAIL);
588 }
589 #endif
590 
591 #ifdef NS_CACHING
592 static int
593 rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
594 {
595 	char *name;
596 	int rpc;
597 
598 	size_t desired_size, size;
599 	enum nss_lookup_type lookup_type;
600 	int res = NS_UNAVAIL;
601 
602 	lookup_type = (enum nss_lookup_type)cache_mdata;
603 	switch (lookup_type) {
604 	case nss_lt_name:
605 		name = va_arg(ap, char *);
606 
607 		size = strlen(name);
608 		desired_size = sizeof(enum nss_lookup_type) + size + 1;
609 		if (desired_size > *buffer_size) {
610 			res = NS_RETURN;
611 			goto fin;
612 		}
613 
614 		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
615 		memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
616 
617 		res = NS_SUCCESS;
618 		break;
619 	case nss_lt_id:
620 		rpc = va_arg(ap, int);
621 
622 		desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
623 		if (desired_size > *buffer_size) {
624 			res = NS_RETURN;
625 			goto fin;
626 		}
627 
628 		memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
629 		memcpy(buffer + sizeof(enum nss_lookup_type), &rpc,
630 		    sizeof(int));
631 
632 		res = NS_SUCCESS;
633 		break;
634 	default:
635 		/* should be unreachable */
636 		return (NS_UNAVAIL);
637 	}
638 
639 fin:
640 	*buffer_size = desired_size;
641 	return (res);
642 }
643 
644 static int
645 rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
646     void *cache_mdata)
647 {
648 	char *name;
649 	int num;
650 	struct rpcent *rpc;
651 	char *orig_buf;
652 	size_t orig_buf_size;
653 
654 	struct rpcent new_rpc;
655 	size_t desired_size, size, aliases_size;
656 	char *p;
657 	char **alias;
658 
659 	switch ((enum nss_lookup_type)cache_mdata) {
660 	case nss_lt_name:
661 		name = va_arg(ap, char *);
662 		break;
663 	case nss_lt_id:
664 		num = va_arg(ap, int);
665 		break;
666 	case nss_lt_all:
667 		break;
668 	default:
669 		/* should be unreachable */
670 		return (NS_UNAVAIL);
671 	}
672 
673 	rpc = va_arg(ap, struct rpcent *);
674 	orig_buf = va_arg(ap, char *);
675 	orig_buf_size = va_arg(ap, size_t);
676 
677 	desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *);
678 	if (rpc->r_name != NULL)
679 		desired_size += strlen(rpc->r_name) + 1;
680 
681 	if (rpc->r_aliases != NULL) {
682 		aliases_size = 0;
683 		for (alias = rpc->r_aliases; *alias; ++alias) {
684 			desired_size += strlen(*alias) + 1;
685 			++aliases_size;
686 		}
687 
688 		desired_size += _ALIGNBYTES + (aliases_size + 1) *
689 		    sizeof(char *);
690 	}
691 
692 	if (*buffer_size < desired_size) {
693 		/* this assignment is here for future use */
694 		*buffer_size = desired_size;
695 		return (NS_RETURN);
696 	}
697 
698 	new_rpc = *rpc;
699 
700 	*buffer_size = desired_size;
701 	memset(buffer, 0, desired_size);
702 	p = buffer + sizeof(struct rpcent) + sizeof(char *);
703 	memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *));
704 	p = (char *)_ALIGN(p);
705 
706 	if (new_rpc.r_name != NULL) {
707 		size = strlen(new_rpc.r_name);
708 		memcpy(p, new_rpc.r_name, size);
709 		new_rpc.r_name = p;
710 		p += size + 1;
711 	}
712 
713 	if (new_rpc.r_aliases != NULL) {
714 		p = (char *)_ALIGN(p);
715 		memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size);
716 		new_rpc.r_aliases = (char **)p;
717 		p += sizeof(char *) * (aliases_size + 1);
718 
719 		for (alias = new_rpc.r_aliases; *alias; ++alias) {
720 			size = strlen(*alias);
721 			memcpy(p, *alias, size);
722 			*alias = p;
723 			p += size + 1;
724 		}
725 	}
726 
727 	memcpy(buffer, &new_rpc, sizeof(struct rpcent));
728 	return (NS_SUCCESS);
729 }
730 
731 static int
732 rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
733     void *cache_mdata)
734 {
735 	char *name;
736 	int num;
737 	struct rpcent *rpc;
738 	char *orig_buf;
739 	size_t orig_buf_size;
740 	int *ret_errno;
741 
742 	char *p;
743 	char **alias;
744 
745 	switch ((enum nss_lookup_type)cache_mdata) {
746 	case nss_lt_name:
747 		name = va_arg(ap, char *);
748 		break;
749 	case nss_lt_id:
750 		num = va_arg(ap, int);
751 		break;
752 	case nss_lt_all:
753 		break;
754 	default:
755 		/* should be unreachable */
756 		return (NS_UNAVAIL);
757 	}
758 
759 	rpc = va_arg(ap, struct rpcent *);
760 	orig_buf = va_arg(ap, char *);
761 	orig_buf_size = va_arg(ap, size_t);
762 	ret_errno = va_arg(ap, int *);
763 
764 	if (orig_buf_size <
765 	    buffer_size - sizeof(struct rpcent) - sizeof(char *)) {
766 		*ret_errno = ERANGE;
767 		return (NS_RETURN);
768 	}
769 
770 	memcpy(rpc, buffer, sizeof(struct rpcent));
771 	memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *));
772 
773 	orig_buf = (char *)_ALIGN(orig_buf);
774 	memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) +
775 	    _ALIGN(p) - (size_t)p,
776 	    buffer_size - sizeof(struct rpcent) - sizeof(char *) -
777 	    _ALIGN(p) + (size_t)p);
778 	p = (char *)_ALIGN(p);
779 
780 	NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *);
781 	if (rpc->r_aliases != NULL) {
782 		NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **);
783 
784 		for (alias = rpc->r_aliases	; *alias; ++alias)
785 			NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
786 	}
787 
788 	if (retval != NULL)
789 		*((struct rpcent **)retval) = rpc;
790 
791 	return (NS_SUCCESS);
792 }
793 
794 NSS_MP_CACHE_HANDLING(rpc);
795 #endif /* NS_CACHING */
796 
797 
798 /* get**_r functions implementation */
799 static int
800 getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer,
801 	size_t bufsize, struct rpcent **result)
802 {
803 #ifdef NS_CACHING
804 	static const nss_cache_info cache_info =
805     		NS_COMMON_CACHE_INFO_INITIALIZER(
806 		rpc, (void *)nss_lt_name,
807 		rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
808 #endif
809 	static const ns_dtab dtab[] = {
810 		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_name },
811 #ifdef YP
812 		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_name },
813 #endif
814 #ifdef NS_CACHING
815 		NS_CACHE_CB(&cache_info)
816 #endif
817 		{ NULL, NULL, NULL }
818 	};
819 	int rv, ret_errno;
820 
821 	ret_errno = 0;
822 	*result = NULL;
823 	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc,
824 	    name, rpc, buffer, bufsize, &ret_errno);
825 
826 	if (rv == NS_SUCCESS)
827 		return (0);
828 	else
829 		return (ret_errno);
830 }
831 
832 static int
833 getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer,
834 	size_t bufsize, struct rpcent **result)
835 {
836 #ifdef NS_CACHING
837 	static const nss_cache_info cache_info =
838     		NS_COMMON_CACHE_INFO_INITIALIZER(
839 		rpc, (void *)nss_lt_id,
840 		rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
841 #endif
842 	static const ns_dtab dtab[] = {
843 		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_id },
844 #ifdef YP
845 		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_id },
846 #endif
847 #ifdef NS_CACHING
848 		NS_CACHE_CB(&cache_info)
849 #endif
850 		{ NULL, NULL, NULL }
851 	};
852 	int rv, ret_errno;
853 
854 	ret_errno = 0;
855 	*result = NULL;
856 	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc,
857 	    number, rpc, buffer, bufsize, &ret_errno);
858 
859 	if (rv == NS_SUCCESS)
860 		return (0);
861 	else
862 		return (ret_errno);
863 }
864 
865 static int
866 getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize,
867 	struct rpcent **result)
868 {
869 #ifdef NS_CACHING
870 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
871 		rpc, (void *)nss_lt_all,
872 		rpc_marshal_func, rpc_unmarshal_func);
873 #endif
874 	static const ns_dtab dtab[] = {
875 		{ NSSRC_FILES, files_rpcent, (void *)nss_lt_all },
876 #ifdef YP
877 		{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_all },
878 #endif
879 #ifdef NS_CACHING
880 		NS_CACHE_CB(&cache_info)
881 #endif
882 		{ NULL, NULL, NULL }
883 	};
884 	int rv, ret_errno;
885 
886 	ret_errno = 0;
887 	*result = NULL;
888 	rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc,
889 	    rpc, buffer, bufsize, &ret_errno);
890 
891 	if (rv == NS_SUCCESS)
892 		return (0);
893 	else
894 		return (ret_errno);
895 }
896 
897 /* get** wrappers for get**_r functions implementation */
898 static 	void
899 rpcent_endstate(void *p)
900 {
901 	if (p == NULL)
902 		return;
903 
904 	free(((struct rpcent_state *)p)->buffer);
905 	free(p);
906 }
907 
908 static	int
909 wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer,
910     size_t bufsize, struct rpcent **res)
911 {
912 	return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res));
913 }
914 
915 static	int
916 wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer,
917     size_t bufsize, struct rpcent **res)
918 {
919 	return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res));
920 }
921 
922 static	int
923 wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer,
924     size_t bufsize, struct rpcent **res)
925 {
926 	return (getrpcent_r(rpc, buffer, bufsize, res));
927 }
928 
929 static struct rpcent *
930 getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **),
931     union key key)
932 {
933 	int		 rv;
934 	struct rpcent	*res;
935 	struct rpcent_state * st;
936 
937 	rv=rpcent_getstate(&st);
938 	if (rv != 0) {
939 		errno = rv;
940 		return NULL;
941 	}
942 
943 	if (st->buffer == NULL) {
944 		st->buffer = malloc(RPCENT_STORAGE_INITIAL);
945 		if (st->buffer == NULL)
946 			return (NULL);
947 		st->bufsize = RPCENT_STORAGE_INITIAL;
948 	}
949 	do {
950 		rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res);
951 		if (res == NULL && rv == ERANGE) {
952 			free(st->buffer);
953 			if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) {
954 				st->buffer = NULL;
955 				errno = ERANGE;
956 				return (NULL);
957 			}
958 			st->bufsize <<= 1;
959 			st->buffer = malloc(st->bufsize);
960 			if (st->buffer == NULL)
961 				return (NULL);
962 		}
963 	} while (res == NULL && rv == ERANGE);
964 	if (rv != 0)
965 		errno = rv;
966 
967 	return (res);
968 }
969 
970 struct rpcent *
971 getrpcbyname(const char *name)
972 {
973 	union key key;
974 
975 	key.name = name;
976 
977 	return (getrpc(wrap_getrpcbyname_r, key));
978 }
979 
980 struct rpcent *
981 getrpcbynumber(int number)
982 {
983 	union key key;
984 
985 	key.number = number;
986 
987 	return (getrpc(wrap_getrpcbynumber_r, key));
988 }
989 
990 struct rpcent *
991 getrpcent(void)
992 {
993 	union key key;
994 
995 	key.number = 0;	/* not used */
996 
997 	return (getrpc(wrap_getrpcent_r, key));
998 }
999 
1000 void
1001 setrpcent(int stayopen)
1002 {
1003 #ifdef NS_CACHING
1004 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1005 		rpc, (void *)nss_lt_all,
1006 		NULL, NULL);
1007 #endif
1008 
1009 	static const ns_dtab dtab[] = {
1010 		{ NSSRC_FILES, files_setrpcent, (void *)SETRPCENT },
1011 #ifdef YP
1012 		{ NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT },
1013 #endif
1014 #ifdef NS_CACHING
1015 		NS_CACHE_CB(&cache_info)
1016 #endif
1017 		{ NULL, NULL, NULL }
1018 	};
1019 
1020 	(void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc,
1021 		stayopen);
1022 }
1023 
1024 void
1025 endrpcent(void)
1026 {
1027 #ifdef NS_CACHING
1028 	static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
1029 		rpc, (void *)nss_lt_all,
1030 		NULL, NULL);
1031 #endif
1032 
1033 	static const ns_dtab dtab[] = {
1034 		{ NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT },
1035 #ifdef YP
1036 		{ NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT },
1037 #endif
1038 #ifdef NS_CACHING
1039 		NS_CACHE_CB(&cache_info)
1040 #endif
1041 		{ NULL, NULL, NULL }
1042 	};
1043 
1044 	(void)nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc);
1045 }
1046