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