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