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