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