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