xref: /illumos-gate/usr/src/cmd/rpcbind/rpcb_svc_com.c (revision 7ae111d47a973fff4c6e231cc31f271dd9cef473)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27 /*
28  * University Copyright- Copyright (c) 1982, 1986, 1988
29  * The Regents of the University of California
30  * All Rights Reserved
31  *
32  * University Acknowledgment- Portions of this document are derived from
33  * software developed by the University of California, Berkeley, and its
34  * contributors.
35  */
36 
37 #pragma ident	"%Z%%M%	%I%	%E% SMI"
38 /*
39  * rpcb_svc_com.c
40  * The commom server procedure for the rpcbind.
41  */
42 
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <rpc/rpc.h>
51 #include <rpc/rpcb_prot.h>
52 #include <netconfig.h>
53 #include <sys/param.h>
54 #include <errno.h>
55 #include <zone.h>
56 #include <sys/poll.h>
57 #include <sys/stropts.h>
58 #ifdef PORTMAP
59 #include <netinet/in.h>
60 #include <rpc/pmap_prot.h>
61 #endif /* PORTMAP */
62 #include <syslog.h>
63 #include <netdir.h>
64 #include <ucred.h>
65 #include <alloca.h>
66 #include <rpcsvc/yp_prot.h>
67 #include <nfs/nfs.h>
68 #include <nfs/nfs_acl.h>
69 #include <rpcsvc/mount.h>
70 #include <nfs/nfs_acl.h>
71 #include <rpc/key_prot.h>
72 #include <rpcsvc/nfsauth_prot.h>
73 #include <rpcsvc/nispasswd.h>
74 #include <rpcsvc/yp_prot.h>
75 #include <rpcsvc/rquota.h>
76 #include <rpcsvc/yppasswd.h>
77 #include <rpcsvc/ypupd.h>
78 #include "rpcbind.h"
79 
80 static bool_t	xdr_opaque_parms();
81 char	*getowner();
82 static ulong_t	forward_register();
83 static void	handle_reply();
84 static int	netbufcmp();
85 static int	free_slot_by_xid();
86 static int	free_slot_by_index();
87 static int	check_rmtcalls();
88 static void	netbuffree();
89 static void	find_versions();
90 static struct netbuf	*netbufdup();
91 static rpcblist_ptr find_service();
92 static int	add_pmaplist(RPCB *);
93 int	del_pmaplist(RPCB *);
94 void	delete_rbl(rpcblist_ptr);
95 
96 static char *nullstring = "";
97 static int rpcb_rmtcalls;
98 
99 /*
100  * Set a mapping of program, version, netid
101  */
102 /* ARGSUSED */
103 bool_t *
104 rpcbproc_set_com(regp, rqstp, transp, rpcbversnum)
105 	RPCB *regp;
106 	struct svc_req *rqstp;	/* Not used here */
107 	SVCXPRT *transp;
108 	int rpcbversnum;
109 {
110 	static bool_t ans;
111 	char owner[64];
112 
113 #ifdef RPCBIND_DEBUG
114 	fprintf(stderr, "RPCB_SET request for (%lu, %lu, %s, %s) : ",
115 		regp->r_prog, regp->r_vers, regp->r_netid, regp->r_addr);
116 #endif
117 	ans = map_set(regp, getowner(transp, owner));
118 #ifdef RPCBIND_DEBUG
119 	fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
120 #endif
121 	/* XXX: should have used some defined constant here */
122 	rpcbs_set((ulong_t)(rpcbversnum - 2), ans);
123 	return (&ans);
124 }
125 
126 bool_t
127 map_set(regp, owner)
128 	RPCB *regp;
129 	char *owner;
130 {
131 	RPCB reg, *a;
132 	rpcblist_ptr rbl, fnd;
133 
134 	reg = *regp;
135 	/*
136 	 * check to see if already used
137 	 * find_service returns a hit even if
138 	 * the versions don't match, so check for it
139 	 */
140 	fnd = find_service(reg.r_prog, reg.r_vers, reg.r_netid);
141 	if (fnd && (fnd->rpcb_map.r_vers == reg.r_vers)) {
142 		if (strcmp(fnd->rpcb_map.r_addr, reg.r_addr) == 0)
143 			/*
144 			 * if these match then it is already
145 			 * registered so just say "OK".
146 			 */
147 			return (TRUE);
148 		else {
149 			/*
150 			 * Check if server is up.  If so, return FALSE.
151 			 * If not, cleanup old registrations for the
152 			 * program and register the new server.
153 			 */
154 			if (is_bound(fnd->rpcb_map.r_netid,
155 							fnd->rpcb_map.r_addr))
156 				return (FALSE);
157 			delete_prog(reg.r_prog);
158 			fnd = NULL;
159 		}
160 	}
161 	/*
162 	 * add to the end of the list
163 	 */
164 	rbl = (rpcblist_ptr) malloc((uint_t)sizeof (RPCBLIST));
165 	if (rbl == (rpcblist_ptr)NULL) {
166 		return (FALSE);
167 	}
168 	a = &(rbl->rpcb_map);
169 	a->r_prog = reg.r_prog;
170 	a->r_vers = reg.r_vers;
171 	a->r_netid = strdup(reg.r_netid);
172 	a->r_addr = strdup(reg.r_addr);
173 	a->r_owner = strdup(owner);
174 	if (a->r_addr == NULL || a->r_netid == NULL|| a->r_owner == NULL) {
175 		delete_rbl(rbl);
176 		return (FALSE);
177 	}
178 	rbl->rpcb_next = (rpcblist_ptr)NULL;
179 	if (list_rbl == NULL) {
180 		list_rbl = rbl;
181 	} else {
182 		for (fnd = list_rbl; fnd->rpcb_next;
183 			fnd = fnd->rpcb_next)
184 			;
185 		fnd->rpcb_next = rbl;
186 	}
187 #ifdef PORTMAP
188 	(void) add_pmaplist(regp);
189 #endif
190 	return (TRUE);
191 }
192 
193 /*
194  * Unset a mapping of program, version, netid
195  */
196 /* ARGSUSED */
197 bool_t *
198 rpcbproc_unset_com(regp, rqstp, transp, rpcbversnum)
199 	RPCB *regp;
200 	struct svc_req *rqstp;	/* Not used here */
201 	SVCXPRT *transp;
202 	int rpcbversnum;
203 {
204 	static bool_t ans;
205 	char owner[64];
206 
207 #ifdef RPCBIND_DEBUG
208 	fprintf(stderr, "RPCB_UNSET request for (%lu, %lu, %s) : ",
209 		regp->r_prog, regp->r_vers, regp->r_netid);
210 #endif
211 	ans = map_unset(regp, getowner(transp, owner));
212 #ifdef RPCBIND_DEBUG
213 	fprintf(stderr, "%s\n", ans == TRUE ? "succeeded" : "failed");
214 #endif
215 	/* XXX: should have used some defined constant here */
216 	rpcbs_unset((ulong_t)(rpcbversnum - 2), ans);
217 	return (&ans);
218 }
219 
220 bool_t
221 map_unset(regp, owner)
222 	RPCB *regp;
223 	char *owner;
224 {
225 #ifdef PORTMAP
226 	int ans = 0;
227 #endif
228 	rpcblist_ptr rbl, next, prev = NULL;
229 
230 	if (owner == NULL)
231 		return (0);
232 
233 	for (rbl = list_rbl; rbl != NULL; rbl = next) {
234 		next = rbl->rpcb_next;
235 
236 		if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
237 		    (rbl->rpcb_map.r_vers != regp->r_vers) ||
238 		    (regp->r_netid[0] && strcasecmp(regp->r_netid,
239 			rbl->rpcb_map.r_netid))) {
240 			/* prev moves forwards */
241 			prev = rbl;
242 			continue;
243 		}
244 		/*
245 		 * Check whether appropriate uid. Unset only
246 		 * if superuser or the owner itself.
247 		 */
248 		if (strcmp(owner, "superuser") &&
249 		    strcmp(rbl->rpcb_map.r_owner, owner))
250 			return (0);
251 		/* prev stays */
252 #ifdef PORTMAP
253 		ans = 1;
254 #endif
255 		delete_rbl(rbl);
256 
257 		if (prev == NULL)
258 			list_rbl = next;
259 		else
260 			prev->rpcb_next = next;
261 	}
262 #ifdef PORTMAP
263 	if (ans)
264 		(void) del_pmaplist(regp);
265 #endif
266 	/*
267 	 * We return 1 either when the entry was not there or it
268 	 * was able to unset it.  It can come to this point only if
269 	 * atleast one of the conditions is true.
270 	 */
271 	return (1);
272 }
273 
274 void
275 delete_rbl(rpcblist_ptr rbl)
276 {
277 	free(rbl->rpcb_map.r_addr);
278 	free(rbl->rpcb_map.r_netid);
279 	free(rbl->rpcb_map.r_owner);
280 	free(rbl);
281 }
282 
283 void
284 delete_prog(prog)
285 	unsigned long prog;
286 {
287 	rpcblist_ptr rbl, next, prev = NULL;
288 
289 	for (rbl = list_rbl; rbl != NULL; rbl = next) {
290 		next = rbl->rpcb_next;
291 
292 		if (rbl->rpcb_map.r_prog != prog ||
293 		    is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr)) {
294 			prev = rbl;
295 			continue;
296 		}
297 
298 #ifdef PORTMAP
299 		(void) del_pmaplist(&rbl->rpcb_map);
300 #endif
301 		delete_rbl(rbl);
302 
303 		if (prev == NULL)
304 			list_rbl = next;
305 		else
306 			prev->rpcb_next = next;
307 	}
308 }
309 
310 /*ARGSUSED*/
311 char **
312 rpcbproc_getaddr_com(regp, rqstp, transp, rpcbversnum, verstype)
313 	RPCB *regp;
314 	struct svc_req *rqstp;	/* Not used here */
315 	SVCXPRT *transp;
316 	ulong_t rpcbversnum;
317 	ulong_t verstype;
318 {
319 	static char *uaddr;
320 	char *saddr = NULL;
321 	rpcblist_ptr fnd;
322 	struct netconfig *trans_conf;	/* transport netconfig */
323 
324 	/*
325 	 * There is a potential window at startup during which rpcbind
326 	 * service has been established over IPv6 but not over IPv4.  If an
327 	 * IPv4 request comes in during that window, the IP code will map
328 	 * it into IPv6.  We could patch up the request so that it looks
329 	 * like IPv4 (so that rpcbind returns an IPv4 uaddr to the caller),
330 	 * but that requires some non-trivial code and it's hard to test.
331 	 * Instead, drop the request on the floor and force the caller to
332 	 * retransmit.  By the time rpcbind sees the retransmission, IPv4
333 	 * service should be in place and it should see the request as
334 	 * IPv4, as desired.
335 	 */
336 	trans_conf = rpcbind_get_conf(transp->xp_netid);
337 	if (strcmp(trans_conf->nc_protofmly, NC_INET6) == 0) {
338 		struct sockaddr_in6 *rmtaddr;
339 
340 		rmtaddr = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
341 		if (IN6_IS_ADDR_V4MAPPED(&rmtaddr->sin6_addr)) {
342 			syslog(LOG_DEBUG,
343 			    "IPv4 GETADDR request mapped to IPv6: ignoring");
344 			return (NULL);
345 		}
346 	}
347 
348 	if (uaddr && uaddr[0])
349 		free((void *) uaddr);
350 	fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
351 	if (fnd && ((verstype == RPCB_ALLVERS) ||
352 		    (regp->r_vers == fnd->rpcb_map.r_vers))) {
353 		if (*(regp->r_addr) != '\0') {  /* may contain a hint about */
354 			saddr = regp->r_addr;   /* the interface that we    */
355 		}				/* should use */
356 		if (!(uaddr = mergeaddr(transp, transp->xp_netid,
357 				fnd->rpcb_map.r_addr, saddr))) {
358 			/* Try whatever we have */
359 			uaddr = strdup(fnd->rpcb_map.r_addr);
360 		} else if (!uaddr[0]) {
361 			/*
362 			 * The server died.  Unset all versions of this prog.
363 			 */
364 			delete_prog(regp->r_prog);
365 			uaddr = nullstring;
366 		}
367 	} else {
368 		uaddr = nullstring;
369 	}
370 #ifdef RPCBIND_DEBUG
371 	fprintf(stderr, "getaddr: %s\n", uaddr);
372 #endif
373 	/* XXX: should have used some defined constant here */
374 	rpcbs_getaddr(rpcbversnum - 2, regp->r_prog, regp->r_vers,
375 		transp->xp_netid, uaddr);
376 	return (&uaddr);
377 }
378 
379 /* VARARGS */
380 ulong_t *
381 rpcbproc_gettime_com()
382 {
383 	static time_t curtime;
384 
385 	(void) time(&curtime);
386 	return ((ulong_t *)&curtime);
387 }
388 
389 /*
390  * Convert uaddr to taddr. Should be used only by
391  * local servers/clients. (kernel level stuff only)
392  */
393 /* ARGSUSED */
394 struct netbuf *
395 rpcbproc_uaddr2taddr_com(uaddrp, rqstp, transp, rpcbversnum)
396 	char **uaddrp;
397 	struct svc_req *rqstp;	/* Not used here */
398 	SVCXPRT *transp;
399 	int rpcbversnum;	/* Not used here */
400 {
401 	struct netconfig *nconf;
402 	static struct netbuf nbuf;
403 	static struct netbuf *taddr;
404 
405 	if (taddr) {
406 		free((void *) taddr->buf);
407 		free((void *) taddr);
408 	}
409 	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
410 	    ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
411 		(void) memset((char *)&nbuf, 0, sizeof (struct netbuf));
412 		return (&nbuf);
413 	}
414 	return (taddr);
415 }
416 
417 /*
418  * Convert taddr to uaddr. Should be used only by
419  * local servers/clients. (kernel level stuff only)
420  */
421 /* ARGSUSED */
422 char **
423 rpcbproc_taddr2uaddr_com(taddr, rqstp, transp, rpcbversnum)
424 	struct netbuf *taddr;
425 	struct svc_req *rqstp;	/* Not used here */
426 	SVCXPRT *transp;
427 	int rpcbversnum; /* unused */
428 {
429 	static char *uaddr;
430 	struct netconfig *nconf;
431 
432 #ifdef CHEW_FDS
433 	int fd;
434 
435 	if ((fd = open("/dev/null", O_RDONLY)) == -1) {
436 		uaddr = (char *)strerror(errno);
437 		return (&uaddr);
438 	}
439 #endif /* CHEW_FDS */
440 	if (uaddr && uaddr[0])
441 		free((void *) uaddr);
442 	if (((nconf = rpcbind_get_conf(transp->xp_netid)) == NULL) ||
443 		((uaddr = taddr2uaddr(nconf, taddr)) == NULL)) {
444 		uaddr = nullstring;
445 	}
446 	return (&uaddr);
447 }
448 
449 
450 /*
451  * Stuff for the rmtcall service
452  */
453 struct encap_parms {
454 	ulong_t arglen;
455 	char *args;
456 };
457 
458 static bool_t
459 xdr_encap_parms(xdrs, epp)
460 	XDR *xdrs;
461 	struct encap_parms *epp;
462 {
463 	return (xdr_bytes(xdrs, &(epp->args), (uint_t *)&(epp->arglen), ~0));
464 }
465 
466 
467 struct r_rmtcall_args {
468 	ulong_t 	rmt_prog;
469 	ulong_t 	rmt_vers;
470 	ulong_t 	rmt_proc;
471 	int	rmt_localvers;	/* whether to send port # or uaddr */
472 	char 	*rmt_uaddr;
473 	struct encap_parms rmt_args;
474 };
475 
476 /*
477  * XDR remote call arguments.  It ignores the address part.
478  * written for XDR_DECODE direction only
479  */
480 static bool_t
481 xdr_rmtcall_args(xdrs, cap)
482 	register XDR *xdrs;
483 	register struct r_rmtcall_args *cap;
484 {
485 	/* does not get the address or the arguments */
486 	if (xdr_u_long(xdrs, &(cap->rmt_prog)) &&
487 	    xdr_u_long(xdrs, &(cap->rmt_vers)) &&
488 	    xdr_u_long(xdrs, &(cap->rmt_proc))) {
489 		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
490 	}
491 	return (FALSE);
492 }
493 
494 /*
495  * XDR remote call results along with the address.  Ignore
496  * program number, version  number and proc number.
497  * Written for XDR_ENCODE direction only.
498  */
499 static bool_t
500 xdr_rmtcall_result(xdrs, cap)
501 	register XDR *xdrs;
502 	register struct r_rmtcall_args *cap;
503 {
504 	bool_t result;
505 
506 #ifdef PORTMAP
507 	if (cap->rmt_localvers == PMAPVERS) {
508 		int h1, h2, h3, h4, p1, p2;
509 		ulong_t port;
510 
511 		/* interpret the universal address for TCP/IP */
512 		if (sscanf(cap->rmt_uaddr, "%d.%d.%d.%d.%d.%d",
513 			&h1, &h2, &h3, &h4, &p1, &p2) != 6)
514 			return (FALSE);
515 		port = ((p1 & 0xff) << 8) + (p2 & 0xff);
516 		result = xdr_u_long(xdrs, &port);
517 	} else
518 #endif
519 		if ((cap->rmt_localvers == RPCBVERS) ||
520 		    (cap->rmt_localvers == RPCBVERS4)) {
521 		result = xdr_wrapstring(xdrs, &(cap->rmt_uaddr));
522 	} else {
523 		return (FALSE);
524 	}
525 	if (result == TRUE)
526 		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
527 	return (FALSE);
528 }
529 
530 /*
531  * only worries about the struct encap_parms part of struct r_rmtcall_args.
532  * The arglen must already be set!!
533  */
534 static bool_t
535 xdr_opaque_parms(xdrs, cap)
536 	XDR *xdrs;
537 	struct r_rmtcall_args *cap;
538 {
539 	return (xdr_opaque(xdrs, cap->rmt_args.args, cap->rmt_args.arglen));
540 }
541 
542 struct rmtcallfd_list {
543 	int fd;
544 	SVCXPRT *xprt;
545 	char *netid;
546 	struct rmtcallfd_list *next;
547 };
548 
549 static struct rmtcallfd_list *rmthead;
550 static struct rmtcallfd_list *rmttail;
551 
552 int
553 create_rmtcall_fd(nconf)
554 struct netconfig *nconf;
555 {
556 	int fd;
557 	struct rmtcallfd_list *rmt;
558 	SVCXPRT *xprt;
559 
560 	if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
561 		if (debugging)
562 			fprintf(stderr,
563 	"create_rmtcall_fd: couldn't open \"%s\" (errno %d, t_errno %d)\n",
564 			nconf->nc_device, errno, t_errno);
565 		return (-1);
566 	}
567 	if (t_bind(fd, (struct t_bind *)0,
568 		(struct t_bind *)0) == -1) {
569 		if (debugging)
570 			fprintf(stderr,
571 "create_rmtcall_fd: couldn't bind to fd for \"%s\" (errno %d, t_errno %d)\n",
572 				nconf->nc_device, errno, t_errno);
573 		return (-1);
574 	}
575 	xprt = svc_tli_create(fd, 0, (struct t_bind *)0, 0, 0);
576 	if (xprt == NULL) {
577 		if (debugging)
578 			fprintf(stderr,
579 				"create_rmtcall_fd: svc_tli_create failed\n");
580 		return (-1);
581 	}
582 	rmt = (struct rmtcallfd_list *)malloc((uint_t)
583 		sizeof (struct rmtcallfd_list));
584 	if (rmt == NULL) {
585 		syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
586 		return (-1);
587 	}
588 	rmt->xprt = xprt;
589 	rmt->netid = strdup(nconf->nc_netid);
590 	xprt->xp_netid = rmt->netid;
591 	rmt->fd = fd;
592 	rmt->next = NULL;
593 	if (rmthead == NULL) {
594 		rmthead = rmt;
595 		rmttail = rmt;
596 	} else {
597 		rmttail->next = rmt;
598 		rmttail = rmt;
599 	}
600 #if defined(DEBUG_RMTCALL) && defined(PORTMAP)
601 	if (debugging) {
602 		struct sockaddr_in *sin;
603 		struct netbuf *nb;
604 		nb = &xprt->xp_ltaddr;
605 		sin = (struct sockaddr_in *)nb->buf;
606 		fprintf(stderr,
607 			"create_rmtcall_fd %d, port %d\n",
608 			fd, sin->sin_port);
609 	}
610 #endif
611 	return (fd);
612 }
613 
614 static int
615 find_rmtcallfd_by_netid(netid)
616 char *netid;
617 {
618 	struct rmtcallfd_list *rmt;
619 
620 	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
621 		if (strcmp(netid, rmt->netid) == 0) {
622 			return (rmt->fd);
623 		}
624 	}
625 	return (-1);
626 }
627 
628 static SVCXPRT *
629 find_rmtcallxprt_by_fd(fd)
630 int fd;
631 {
632 	struct rmtcallfd_list *rmt;
633 
634 	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
635 		if (fd == rmt->fd) {
636 			return (rmt->xprt);
637 		}
638 	}
639 	return (NULL);
640 }
641 
642 
643 /*
644  * Call a remote procedure service.  This procedure is very quiet when things
645  * go wrong.  The proc is written to support broadcast rpc.  In the broadcast
646  * case, a machine should shut-up instead of complain, lest the requestor be
647  * overrun with complaints at the expense of not hearing a valid reply.
648  * When receiving a request and verifying that the service exists, we
649  *
650  *	receive the request
651  *
652  *	open a new TLI endpoint on the same transport on which we received
653  *	the original request
654  *
655  *	remember the original request's XID (which requires knowing the format
656  *	of the svc_dg_data structure)
657  *
658  *	forward the request, with a new XID, to the requested service,
659  *	remembering the XID used to send this request (for later use in
660  *	reassociating the answer with the original request), the requestor's
661  *	address, the file descriptor on which the forwarded request is
662  *	made and the service's address.
663  *
664  *	mark the file descriptor on which we anticipate receiving a reply from
665  *	the service and one to select for in our private svc_run procedure
666  *
667  * At some time in the future, a reply will be received from the service to
668  * which we forwarded the request.  At that time, we detect that the socket
669  * used was for forwarding (by looking through the finfo structures to see
670  * whether the fd corresponds to one of those) and call handle_reply() to
671  *
672  *	receive the reply
673  *
674  *	bundle the reply, along with the service's universal address
675  *
676  *	create a SVCXPRT structure and use a version of svc_sendreply
677  *	that allows us to specify the reply XID and destination, send the reply
678  *	to the original requestor.
679  */
680 
681 /*	begin kludge XXX */
682 /*
683  * This is from .../libnsl/rpc/svc_dg.c, and is the structure that xprt->xp_p2
684  * points to (and shouldn't be here - we should know nothing of its structure).
685  */
686 #define	MAX_OPT_WORDS	128
687 #define	RPC_BUF_MAX	65536	/* can be raised if required */
688 struct svc_dg_data {
689 	/* XXX: optbuf should be the first field, used by ti_opts.c code */
690 	struct  netbuf optbuf;			/* netbuf for options */
691 	long    opts[MAX_OPT_WORDS];		/* options */
692 	uint_t   su_iosz;			/* size of send.recv buffer */
693 	ulong_t  su_xid;				/* transaction id */
694 	XDR	su_xdrs;			/* XDR handle */
695 	char    su_verfbody[MAX_AUTH_BYTES];	/* verifier body */
696 	char    *su_cache;			/* cached data, NULL if none */
697 	struct t_unitdata   su_tudata;		/* tu_data for recv */
698 };
699 #define	getbogus_data(xprt) ((struct svc_dg_data *)(xprt->xp_p2))
700 
701 /*
702  *  This is from ../ypcmd/yp_b.h
703  *  It does not appear in <rpcsvc/yp_prot.h>
704  */
705 #define	YPBINDPROG ((ulong_t)100007)
706 #define	YPBINDPROC_SETDOM ((ulong_t)2)
707 
708 /*	end kludge XXX	*/
709 
710 void
711 rpcbproc_callit_com(rqstp, transp, reply_type, versnum)
712 	struct svc_req *rqstp;
713 	SVCXPRT *transp;
714 	ulong_t reply_type;	/* which proc number */
715 	ulong_t versnum;	/* which vers was called */
716 {
717 	register rpcblist_ptr rbl;
718 	struct netconfig *nconf;
719 	struct netbuf *caller;
720 	struct r_rmtcall_args a;
721 	char *buf_alloc = NULL;
722 	char *outbuf_alloc = NULL;
723 	char buf[RPC_BUF_MAX], outbuf[RPC_BUF_MAX];
724 	struct netbuf *na = (struct netbuf *)NULL;
725 	struct t_info tinfo;
726 	struct t_unitdata tu_data;
727 	struct rpc_msg call_msg;
728 	struct svc_dg_data *bd;
729 	int outlen;
730 	uint_t sendsz;
731 	XDR outxdr;
732 	AUTH *auth;
733 	int fd = -1;
734 	char *uaddr;
735 	struct nd_mergearg ma;
736 	int stat;
737 
738 	if (t_getinfo(transp->xp_fd, &tinfo) == -1) {
739 		if (reply_type == RPCBPROC_INDIRECT)
740 			svcerr_systemerr(transp);
741 		return;
742 	}
743 	if (tinfo.servtype != T_CLTS)
744 		return;	/* Only datagram type accepted */
745 	sendsz = __rpc_get_t_size(0, tinfo.tsdu);
746 	if (sendsz == 0) {	/* data transfer not supported */
747 		if (reply_type == RPCBPROC_INDIRECT)
748 			svcerr_systemerr(transp);
749 		return;
750 	}
751 	/*
752 	 * Should be multiple of 4 for XDR.
753 	 */
754 	sendsz = ((sendsz + 3) / 4) * 4;
755 	if (sendsz > RPC_BUF_MAX) {
756 #ifdef	notyet
757 		buf_alloc = alloca(sendsz);		/* not in IDR2? */
758 #else
759 		buf_alloc = malloc(sendsz);
760 #endif	/* notyet */
761 		if (buf_alloc == NULL) {
762 			if (debugging)
763 				fprintf(stderr,
764 					"rpcbproc_callit_com:  No Memory!\n");
765 			if (reply_type == RPCBPROC_INDIRECT)
766 				svcerr_systemerr(transp);
767 			return;
768 		}
769 		a.rmt_args.args = buf_alloc;
770 	} else {
771 		a.rmt_args.args = buf;
772 	}
773 
774 	call_msg.rm_xid = 0;	/* For error checking purposes */
775 	ma.m_uaddr = NULL;
776 	if (!svc_getargs(transp, (xdrproc_t)xdr_rmtcall_args, (char *)&a)) {
777 		if (reply_type == RPCBPROC_INDIRECT)
778 			svcerr_decode(transp);
779 		if (debugging)
780 			fprintf(stderr,
781 			"rpcbproc_callit_com:  svc_getargs failed\n");
782 		goto error;
783 	}
784 	if (!allow_indirect)
785 		goto error;
786 	caller = svc_getrpccaller(transp);
787 #ifdef RPCBIND_DEBUG
788 	uaddr = taddr2uaddr(rpcbind_get_conf(transp->xp_netid), caller);
789 	fprintf(stderr, "%s %s request for (%lu, %lu, %lu, %s) from %s : ",
790 		versnum == PMAPVERS ? "pmap_rmtcall" :
791 		versnum == RPCBVERS ? "rpcb_rmtcall" :
792 		versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown",
793 		reply_type == RPCBPROC_INDIRECT ? "indirect" : "callit",
794 		a.rmt_prog, a.rmt_vers, a.rmt_proc, transp->xp_netid,
795 		uaddr ? uaddr : "unknown");
796 	if (uaddr)
797 		free((void *) uaddr);
798 #endif
799 
800 	/*
801 	 * Disallow calling rpcbind for certain procedures.
802 	 * Allow calling NULLPROC - per man page on rpcb_rmtcall().
803 	 * switch is in alphabetical order.
804 	 */
805 	if (a.rmt_proc != NULLPROC) {
806 		switch (a.rmt_prog) {
807 		case KEY_PROG:
808 			if (debugging)
809 				fprintf(stderr,
810 					"rpcbind: rejecting KEY_PROG(%d)\n",
811 					a.rmt_proc);
812 			goto error;
813 		case MOUNTPROG:
814 			if (a.rmt_proc != MOUNTPROC_MNT)
815 				break;
816 			/*
817 			 * In Solaris 2.6, the host-based accesss control
818 			 * is done by the NFS server on each request.
819 			 * Prior to 2.6 we rely on mountd.
820 			 */
821 			if (debugging)
822 				fprintf(stderr,
823 					"rpcbind: rejecting MOUNTPROG(%d)\n",
824 					a.rmt_proc);
825 			goto error;
826 		case NFSAUTH_PROG:
827 			if (debugging)
828 				fprintf(stderr,
829 					"rpcbind: rejecting NFSAUTH_PROG(%d)\n",
830 					a.rmt_proc);
831 			goto error;
832 		case NFS_ACL_PROGRAM:
833 			if (debugging)
834 				fprintf(stderr,
835 				"rpcbind: rejecting NFS_ACL_PROGRAM(%d)\n",
836 					a.rmt_proc);
837 			goto error;
838 		case NFS_PROGRAM:
839 			/* also NFS3_PROGRAM */
840 			if (debugging)
841 				fprintf(stderr,
842 					"rpcbind: rejecting NFS_PROGRAM(%d)\n",
843 					a.rmt_proc);
844 			goto error;
845 		case RPCBPROG:
846 			/*
847 			 * Disallow calling rpcbind for certain procedures.
848 			 * Luckily Portmap set/unset/callit also have same
849 			 * procedure numbers.  So, will not check for those.
850 			 */
851 			switch (a.rmt_proc) {
852 			case RPCBPROC_SET:
853 			case RPCBPROC_UNSET:
854 			case RPCBPROC_CALLIT:
855 			case RPCBPROC_INDIRECT:
856 				if (reply_type == RPCBPROC_INDIRECT)
857 					svcerr_weakauth(transp); /* XXX */
858 				if (debugging)
859 					fprintf(stderr,
860 "rpcbproc_callit_com: calling RPCBPROG procs SET, UNSET, CALLIT, or INDIRECT \
861 not allowed	\n");
862 				goto error;
863 			default:
864 				/*
865 				 * Ideally, we should have called rpcb_service()
866 				 * or pmap_service() with appropriate parameters
867 				 * instead of going about in a roundabout
868 				 * manner.  Hopefully, this case should happen
869 				 * rarely.
870 				 */
871 				break;
872 			}
873 			break;
874 		case RQUOTAPROG:
875 			if (debugging)
876 				fprintf(stderr,
877 					"rpcbind: rejecting RQUOTAPROG(%d)\n",
878 					a.rmt_proc);
879 			goto error;
880 		case YPPASSWDPROG:
881 			if (debugging)
882 				fprintf(stderr,
883 					"rpcbind: rejecting YPPASSWDPROG(%d)\n",
884 					a.rmt_proc);
885 			goto error;
886 		case YPU_PROG:
887 			if (debugging)
888 				fprintf(stderr,
889 					"rpcbind: rejecting YPU_PROG(%d)\n",
890 					a.rmt_proc);
891 			goto error;
892 		case YPBINDPROG:
893 			if (a.rmt_proc != YPBINDPROC_SETDOM)
894 				break;
895 			if (debugging)
896 				fprintf(stderr,
897 					"rpcbind: rejecting YPBINDPROG(%d)\n",
898 					a.rmt_proc);
899 			goto error;
900 		case YPPROG:
901 			switch (a.rmt_proc) {
902 			case YPPROC_FIRST:
903 			case YPPROC_NEXT:
904 			case YPPROC_MATCH:
905 			case YPPROC_ALL:
906 				if (debugging)
907 					fprintf(stderr,
908 					"rpcbind: rejecting YPPROG(%d)\n",
909 						a.rmt_proc);
910 				goto error;
911 			default:
912 				break;
913 			}
914 			break;
915 		default:
916 			break;
917 		}
918 	}
919 
920 	rbl = find_service(a.rmt_prog, a.rmt_vers, transp->xp_netid);
921 
922 	rpcbs_rmtcall(versnum - 2, reply_type, a.rmt_prog, a.rmt_vers,
923 			a.rmt_proc, transp->xp_netid, rbl);
924 
925 	if (rbl == (rpcblist_ptr)NULL) {
926 #ifdef RPCBIND_DEBUG
927 		fprintf(stderr, "not found\n");
928 #endif
929 		if (reply_type == RPCBPROC_INDIRECT)
930 			svcerr_noprog(transp);
931 		goto error;
932 	}
933 	if (rbl->rpcb_map.r_vers != a.rmt_vers) {
934 #ifdef RPCBIND_DEBUG
935 		fprintf(stderr, "version not found\n");
936 #endif
937 		if (reply_type == RPCBPROC_INDIRECT) {
938 			ulong_t vers_low, vers_high;
939 
940 			find_versions(a.rmt_prog, transp->xp_netid,
941 				&vers_low, &vers_high);
942 			svcerr_progvers(transp, vers_low, vers_high);
943 		}
944 		goto error;
945 	}
946 
947 #ifdef RPCBIND_DEBUG
948 	fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr);
949 #endif
950 	/*
951 	 *	Check whether this entry is valid and a server is present
952 	 *	Mergeaddr() returns NULL if no such entry is present, and
953 	 *	returns "" if the entry was present but the server is not
954 	 *	present (i.e., it crashed).
955 	 */
956 	if (reply_type == RPCBPROC_INDIRECT) {
957 		uaddr = mergeaddr(transp, transp->xp_netid,
958 			rbl->rpcb_map.r_addr, NULL);
959 		if ((uaddr == (char *)NULL) || uaddr[0] == '\0') {
960 			svcerr_noprog(transp);
961 			goto error;
962 		} else {
963 			free((void *) uaddr);
964 		}
965 	}
966 	nconf = rpcbind_get_conf(transp->xp_netid);
967 	if (nconf == (struct netconfig *)NULL) {
968 		if (reply_type == RPCBPROC_INDIRECT)
969 			svcerr_systemerr(transp);
970 		if (debugging)
971 			fprintf(stderr,
972 			"rpcbproc_callit_com:  rpcbind_get_conf failed\n");
973 		goto error;
974 	}
975 	ma.c_uaddr = taddr2uaddr(nconf, caller);
976 	ma.s_uaddr = rbl->rpcb_map.r_addr;
977 	/*
978 	 *	A mergeaddr operation allocates a string, which it stores in
979 	 *	ma.m_uaddr.  It's passed to forward_register() and is
980 	 *	eventually freed by free_slot_*().
981 	 */
982 
983 	stat = netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma);
984 	free((void *) ma.c_uaddr);
985 	if (stat)
986 		(void) syslog(LOG_ERR, "netdir_merge failed for %s: %s",
987 			nconf->nc_netid, netdir_sperror());
988 #ifdef ND_DEBUG
989 fprintf(stderr,
990 "rpcbproc_callit_com: s_uaddr = %s, c_uaddr = %s, merged m_uaddr = %s\n",
991 				ma.s_uaddr, ma.c_uaddr, ma.m_uaddr);
992 #endif
993 	if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
994 		if (reply_type == RPCBPROC_INDIRECT)
995 			svcerr_systemerr(transp);
996 		free((void *) ma.m_uaddr);
997 		ma.m_uaddr = NULL;
998 		goto error;
999 	}
1000 	bd = getbogus_data(transp);
1001 	call_msg.rm_xid = forward_register(bd->su_xid,
1002 			caller, fd, ma.m_uaddr, reply_type, versnum);
1003 	if (call_msg.rm_xid == 0) {
1004 		/*
1005 		 * A duplicate request for the slow server.  Let's not
1006 		 * beat on it any more.
1007 		 */
1008 		if (debugging)
1009 			fprintf(stderr,
1010 			"rpcbproc_callit_com:  duplicate request\n");
1011 		free((void *) ma.m_uaddr);
1012 		ma.m_uaddr = NULL;
1013 		goto error;
1014 	} else 	if (call_msg.rm_xid == (uint32_t)-1) {
1015 		/*  forward_register failed.  Perhaps no memory. */
1016 		if (debugging)
1017 			fprintf(stderr,
1018 			"rpcbproc_callit_com:  forward_register failed\n");
1019 		free((void *) ma.m_uaddr);
1020 		ma.m_uaddr = NULL;
1021 		goto error;
1022 	}
1023 
1024 #ifdef DEBUG_RMTCALL
1025 	fprintf(stderr,
1026 		"rpcbproc_callit_com:  original XID %x, new XID %x\n",
1027 			bd->su_xid, call_msg.rm_xid);
1028 #endif
1029 	call_msg.rm_direction = CALL;
1030 	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
1031 	call_msg.rm_call.cb_prog = a.rmt_prog;
1032 	call_msg.rm_call.cb_vers = a.rmt_vers;
1033 	if (sendsz > RPC_BUF_MAX) {
1034 #ifdef	notyet
1035 		outbuf_alloc = alloca(sendsz);	/* not in IDR2? */
1036 #else
1037 		outbuf_alloc = malloc(sendsz);
1038 #endif	/* notyet */
1039 		if (outbuf_alloc == NULL) {
1040 			if (reply_type == RPCBPROC_INDIRECT)
1041 				svcerr_systemerr(transp);
1042 			if (debugging)
1043 				fprintf(stderr,
1044 				"rpcbproc_callit_com:  No memory!\n");
1045 			goto error;
1046 		}
1047 		xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
1048 	} else {
1049 		xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
1050 	}
1051 	if (!xdr_callhdr(&outxdr, &call_msg)) {
1052 		if (reply_type == RPCBPROC_INDIRECT)
1053 			svcerr_systemerr(transp);
1054 		if (debugging)
1055 			fprintf(stderr,
1056 			"rpcbproc_callit_com:  xdr_callhdr failed\n");
1057 		goto error;
1058 	}
1059 	if (!xdr_u_long(&outxdr, &(a.rmt_proc))) {
1060 		if (reply_type == RPCBPROC_INDIRECT)
1061 			svcerr_systemerr(transp);
1062 		if (debugging)
1063 			fprintf(stderr,
1064 			"rpcbproc_callit_com:  xdr_u_long failed\n");
1065 		goto error;
1066 	}
1067 
1068 	if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
1069 		auth = authnone_create();
1070 	} else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
1071 		struct authsys_parms *au;
1072 
1073 		au = (struct authsys_parms *)rqstp->rq_clntcred;
1074 		auth = authsys_create(au->aup_machname,
1075 				au->aup_uid, au->aup_gid,
1076 				au->aup_len, au->aup_gids);
1077 		if (auth == NULL) /* fall back */
1078 			auth = authnone_create();
1079 	} else {
1080 		/* we do not support any other authentication scheme */
1081 		if (debugging)
1082 			fprintf(stderr,
1083 "rpcbproc_callit_com:  oa_flavor != AUTH_NONE and oa_flavor != AUTH_SYS\n");
1084 		if (reply_type == RPCBPROC_INDIRECT)
1085 			svcerr_weakauth(transp); /* XXX too strong.. */
1086 		goto error;
1087 	}
1088 	if (auth == NULL) {
1089 		if (reply_type == RPCBPROC_INDIRECT)
1090 			svcerr_systemerr(transp);
1091 		if (debugging)
1092 			fprintf(stderr,
1093 		"rpcbproc_callit_com:  authwhatever_create returned NULL\n");
1094 		goto error;
1095 	}
1096 	if (!AUTH_MARSHALL(auth, &outxdr)) {
1097 		if (reply_type == RPCBPROC_INDIRECT)
1098 			svcerr_systemerr(transp);
1099 		AUTH_DESTROY(auth);
1100 		if (debugging)
1101 			fprintf(stderr,
1102 		"rpcbproc_callit_com:  AUTH_MARSHALL failed\n");
1103 		goto error;
1104 	}
1105 	AUTH_DESTROY(auth);
1106 	if (!xdr_opaque_parms(&outxdr, &a)) {
1107 		if (reply_type == RPCBPROC_INDIRECT)
1108 			svcerr_systemerr(transp);
1109 		if (debugging)
1110 			fprintf(stderr,
1111 		"rpcbproc_callit_com:  xdr_opaque_parms failed\n");
1112 		goto error;
1113 	}
1114 	outlen = (int)XDR_GETPOS(&outxdr);
1115 	if (outbuf_alloc)
1116 		tu_data.udata.buf = outbuf_alloc;
1117 	else
1118 		tu_data.udata.buf = outbuf;
1119 	tu_data.udata.len = outlen;
1120 	tu_data.opt.len = 0;
1121 
1122 	na = uaddr2taddr(nconf, ma.m_uaddr);
1123 	if (!na) {
1124 		if (reply_type == RPCBPROC_INDIRECT)
1125 			svcerr_systemerr(transp);
1126 		goto error;
1127 	}
1128 	tu_data.addr = *na;
1129 
1130 	if (t_sndudata(fd, &tu_data) == -1) {
1131 		if (debugging)
1132 			fprintf(stderr,
1133 	"rpcbproc_callit_com:  t_sndudata failed:  t_errno %d, errno %d\n",
1134 				t_errno, errno);
1135 		if (reply_type == RPCBPROC_INDIRECT)
1136 			svcerr_systemerr(transp);
1137 		goto error;
1138 	}
1139 	goto out;
1140 
1141 error:
1142 	if ((call_msg.rm_xid != 0) && (ma.m_uaddr != NULL))
1143 		(void) free_slot_by_xid(call_msg.rm_xid, ma.m_uaddr);
1144 out:
1145 	if (buf_alloc)
1146 		free((void *) buf_alloc);
1147 	if (outbuf_alloc)
1148 		free((void *) outbuf_alloc);
1149 	if (na)
1150 		netdir_free((char *)na, ND_ADDR);
1151 }
1152 
1153 #define	NFORWARD	64
1154 #define	MAXTIME_OFF	300	/* 5 minutes */
1155 
1156 struct finfo {
1157 	int		flag;
1158 #define	FINFO_ACTIVE	0x1
1159 	ulong_t		caller_xid;
1160 	struct netbuf	*caller_addr;
1161 	ulong_t		forward_xid;
1162 	int		forward_fd;
1163 	char		*uaddr;
1164 	ulong_t		reply_type;
1165 	ulong_t		versnum;
1166 	time_t		time;
1167 };
1168 static struct finfo	FINFO[NFORWARD];
1169 /*
1170  * Makes an entry into the FIFO for the given request.
1171  * If duplicate request, returns a 0, else returns the xid of its call.
1172  */
1173 static ulong_t
1174 forward_register(caller_xid, caller_addr, forward_fd, uaddr,
1175 	reply_type, versnum)
1176 	ulong_t		caller_xid;
1177 	struct netbuf	*caller_addr;
1178 	int		forward_fd;
1179 	char		*uaddr;
1180 	ulong_t		reply_type;
1181 	ulong_t		versnum;
1182 {
1183 	int		i;
1184 	int		j = 0;
1185 	time_t		min_time, time_now;
1186 	static ulong_t	lastxid;
1187 	int		entry = -1;
1188 
1189 	min_time = FINFO[0].time;
1190 	time_now = time((time_t *)0);
1191 	/*
1192 	 * initialization: once this has happened, lastxid will
1193 	 * - always be a multiple of NFORWARD (which has to be a power of 2),
1194 	 * - never be 0 again,
1195 	 * - never be (ulong_t)(-NFORWARD)
1196 	 * when entering or returning from this function.
1197 	 */
1198 	if (lastxid == 0) {
1199 		lastxid = time_now * NFORWARD;
1200 		/*
1201 		 * avoid lastxid wraparound to 0,
1202 		 *  and generating a forward_xid of -1
1203 		 */
1204 		if (lastxid >= (ulong_t)(-NFORWARD))
1205 			lastxid = NFORWARD;
1206 	}
1207 
1208 	/*
1209 	 * Check if it is an duplicate entry. Then,
1210 	 * try to find an empty slot.  If not available, then
1211 	 * use the slot with the earliest time.
1212 	 */
1213 	for (i = 0; i < NFORWARD; i++) {
1214 		if (FINFO[i].flag & FINFO_ACTIVE) {
1215 			if ((FINFO[i].caller_xid == caller_xid) &&
1216 			    (FINFO[i].reply_type == reply_type) &&
1217 			    (FINFO[i].versnum == versnum) &&
1218 			    (!netbufcmp(FINFO[i].caller_addr,
1219 					    caller_addr))) {
1220 				FINFO[i].time = time((time_t *)0);
1221 				return (0);	/* Duplicate entry */
1222 			} else {
1223 				/* Should we wait any longer */
1224 				if ((time_now - FINFO[i].time) > MAXTIME_OFF)
1225 					(void) free_slot_by_index(i);
1226 			}
1227 		}
1228 		if (entry == -1) {
1229 			if ((FINFO[i].flag & FINFO_ACTIVE) == 0) {
1230 				entry = i;
1231 			} else if (FINFO[i].time < min_time) {
1232 				j = i;
1233 				min_time = FINFO[i].time;
1234 			}
1235 		}
1236 	}
1237 	if (entry != -1) {
1238 		/* use this empty slot */
1239 		j = entry;
1240 	} else {
1241 		(void) free_slot_by_index(j);
1242 	}
1243 	if ((FINFO[j].caller_addr = netbufdup(caller_addr)) == NULL) {
1244 		return ((ulong_t)-1);
1245 	}
1246 	rpcb_rmtcalls++;	/* no of pending calls */
1247 	FINFO[j].flag = FINFO_ACTIVE;
1248 	FINFO[j].reply_type = reply_type;
1249 	FINFO[j].versnum = versnum;
1250 	FINFO[j].time = time_now;
1251 	FINFO[j].caller_xid = caller_xid;
1252 	FINFO[j].forward_fd = forward_fd;
1253 	/*
1254 	 * Though uaddr is not allocated here, it will still be freed
1255 	 * from free_slot_*().
1256 	 */
1257 	FINFO[j].uaddr = uaddr;
1258 	lastxid = lastxid + NFORWARD;
1259 	/* avoid lastxid wraparound to 0, and generating a forward_xid of -1 */
1260 	if (lastxid >= (ulong_t)(-NFORWARD))
1261 		lastxid = NFORWARD;
1262 
1263 	FINFO[j].forward_xid = lastxid + j;	/* encode slot */
1264 	return (FINFO[j].forward_xid);		/* forward on this xid */
1265 }
1266 
1267 static struct finfo *
1268 forward_find(reply_xid, uaddr)
1269 	ulong_t		reply_xid;
1270 	char		*uaddr;
1271 {
1272 	int		i;
1273 
1274 	i = reply_xid % NFORWARD;
1275 	if (i < 0)
1276 		i += NFORWARD;
1277 	if ((FINFO[i].flag & FINFO_ACTIVE) &&
1278 	    (strcmp(FINFO[i].uaddr, uaddr) == 0) &&
1279 	    (FINFO[i].forward_xid == reply_xid)) {
1280 		return (&FINFO[i]);
1281 	}
1282 	return (NULL);
1283 }
1284 
1285 static int
1286 free_slot_by_xid(xid, uaddr)
1287 	ulong_t xid;
1288 	char   *uaddr;
1289 {
1290 	int entry;
1291 
1292 	if (forward_find(xid, uaddr)) {
1293 		entry = xid % NFORWARD;
1294 		if (entry < 0)
1295 			entry += NFORWARD;
1296 		return (free_slot_by_index(entry));
1297 	}
1298 	return (0);
1299 }
1300 
1301 static int
1302 free_slot_by_index(index)
1303 	int index;
1304 {
1305 	struct finfo	*fi;
1306 
1307 	fi = &FINFO[index];
1308 	if (fi->flag & FINFO_ACTIVE) {
1309 		netbuffree(fi->caller_addr);
1310 		free((void *) fi->uaddr);
1311 		fi->flag &= ~FINFO_ACTIVE;
1312 		rpcb_rmtcalls--;
1313 		return (1);
1314 	}
1315 	return (0);
1316 }
1317 
1318 static int
1319 netbufcmp(n1, n2)
1320 	struct netbuf	*n1, *n2;
1321 {
1322 	return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
1323 }
1324 
1325 static struct netbuf *
1326 netbufdup(ap)
1327 	register struct netbuf  *ap;
1328 {
1329 	register struct netbuf  *np;
1330 
1331 	np = (struct netbuf *) malloc(sizeof (struct netbuf) + ap->len);
1332 	if (np) {
1333 		np->maxlen = np->len = ap->len;
1334 		np->buf = ((char *)np) + sizeof (struct netbuf);
1335 		(void) memcpy(np->buf, ap->buf, ap->len);
1336 	}
1337 	return (np);
1338 }
1339 
1340 static void
1341 netbuffree(ap)
1342 	register struct netbuf  *ap;
1343 {
1344 	free((void *) ap);
1345 }
1346 
1347 /*
1348  * active_fd is used to determine whether an entry in svc_pollfd is:
1349  *    1. not a forward fd (should be polled)
1350  *    2. an active forward fd (should be polled)
1351  *    3. an inactive forward fd (should not be polled)
1352  */
1353 static bool_t
1354 active_fd(fd)
1355 	int fd;
1356 {
1357 	int i;
1358 	time_t time_now;
1359 
1360 	if (find_rmtcallxprt_by_fd(fd) == (SVCXPRT *)NULL)
1361 		return (TRUE);
1362 	if (rpcb_rmtcalls == 0)
1363 		return (FALSE);
1364 	time_now = time((time_t *)0);
1365 	for (i = 0; i < NFORWARD; i++)
1366 		if (FINFO[i].forward_fd == fd) {
1367 			if (FINFO[i].flag & FINFO_ACTIVE) {
1368 			/* Should we wait any longer */
1369 				if ((time_now - FINFO[i].time) > MAXTIME_OFF)
1370 					(void) free_slot_by_index(i);
1371 				else
1372 					return (TRUE);
1373 			}
1374 		}
1375 	return (FALSE);
1376 }
1377 
1378 #define	MASKVAL	(POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
1379 
1380 void
1381 my_svc_run()
1382 {
1383 	size_t nfds;
1384 	struct pollfd pollfds[FD_SETSIZE];
1385 	int poll_ret, check_ret;
1386 #ifdef SVC_RUN_DEBUG
1387 	int i;
1388 #endif
1389 	register struct pollfd	*p;
1390 
1391 	for (;;) {
1392 		{
1393 			register pollfd_t *in;
1394 			register int n;		/* loop counter */
1395 
1396 			/*
1397 			 * compress the sparse svc_pollfd strcutre
1398 			 * into pollfds
1399 			 */
1400 			memset(pollfds, 0, sizeof (pollfds));
1401 			p = pollfds;
1402 			for (in = svc_pollfd, n = 0; n < svc_max_pollfd;
1403 					n++, in++) {
1404 				if ((in->fd >= 0) && active_fd(in->fd)) {
1405 					p->fd = in->fd;
1406 					p->events = MASKVAL;
1407 					p->revents = 0;
1408 					p++;
1409 				}
1410 			}
1411 			nfds = p - pollfds;
1412 		}
1413 		poll_ret = 0;
1414 #ifdef SVC_RUN_DEBUG
1415 		if (debugging) {
1416 			fprintf(stderr, "polling for read on fd < ");
1417 			for (i = 0, p = pollfds; i < nfds; i++, p++)
1418 				if (p->events)
1419 					fprintf(stderr, "%d ", p->fd);
1420 			fprintf(stderr, ">\n");
1421 		}
1422 #endif
1423 		switch (poll_ret = poll(pollfds, nfds, INFTIM)) {
1424 		case -1:
1425 			/*
1426 			 * We ignore all errors, continuing with the assumption
1427 			 * that it was set by the signal handlers (or any
1428 			 * other outside event) and not caused by poll().
1429 			 * If it was our refresh signal, call the refresh
1430 			 * function.
1431 			 */
1432 			if (sigrefresh) {
1433 				sigrefresh = 0;
1434 				rpcb_check_init();
1435 			}
1436 		case 0:
1437 			continue;
1438 		default:
1439 #ifdef SVC_RUN_DEBUG
1440 			if (debugging) {
1441 				fprintf(stderr, "poll returned read fds < ");
1442 				for (i = 0, p = pollfds; i < nfds; i++, p++)
1443 					if (p->revents)
1444 						fprintf(stderr, "%d ", p->fd);
1445 				fprintf(stderr, ">\n");
1446 			}
1447 #endif
1448 			/*
1449 			 * If we found as many replies on callback fds
1450 			 * as the number of descriptors selectable which
1451 			 * poll() returned, there can be no more so we
1452 			 * don't call svc_getreq_poll.  Otherwise, there
1453 			 * must be another so we must call svc_getreq_poll.
1454 			 */
1455 			if ((check_ret = check_rmtcalls(pollfds, nfds)) ==
1456 			    poll_ret)
1457 				continue;
1458 			svc_getreq_poll(pollfds, poll_ret-check_ret);
1459 		}
1460 	}
1461 }
1462 
1463 static int
1464 check_rmtcalls(pfds, nfds)
1465 	struct pollfd *pfds;
1466 	int nfds;
1467 {
1468 	int j, ncallbacks_found = 0;
1469 	SVCXPRT *xprt;
1470 
1471 	/*
1472 	 * This fd will not be polled if rpcb_rmtcalls == 0
1473 	 */
1474 	if (rpcb_rmtcalls == 0)
1475 		return (0);
1476 
1477 	for (j = 0; j < nfds; j++) {
1478 		if ((xprt = find_rmtcallxprt_by_fd(pfds[j].fd)) != NULL) {
1479 			if (pfds[j].revents) {
1480 				ncallbacks_found++;
1481 #ifdef DEBUG_RMTCALL
1482 			if (debugging)
1483 				fprintf(stderr,
1484 "my_svc_run:  polled on forwarding fd %d, netid %s - calling handle_reply\n",
1485 		pfds[j].fd, xprt->xp_netid);
1486 #endif
1487 				handle_reply(pfds[j].fd, xprt);
1488 				pfds[j].revents = 0;
1489 			}
1490 		}
1491 	}
1492 	return (ncallbacks_found);
1493 }
1494 
1495 static void
1496 xprt_set_caller(xprt, fi)
1497 	SVCXPRT *xprt;
1498 	struct finfo *fi;
1499 {
1500 	struct svc_dg_data *bd;
1501 
1502 	*(svc_getrpccaller(xprt)) = *(fi->caller_addr);
1503 	bd = (struct svc_dg_data *)getbogus_data(xprt);
1504 	bd->su_xid = fi->caller_xid;	/* set xid on reply */
1505 }
1506 
1507 /*
1508  * Call svcerr_systemerr() only if RPCBVERS4
1509  */
1510 static void
1511 send_svcsyserr(xprt, fi)
1512 	SVCXPRT *xprt;
1513 	struct finfo	*fi;
1514 {
1515 	if (fi->reply_type == RPCBPROC_INDIRECT) {
1516 		xprt_set_caller(xprt, fi);
1517 		svcerr_systemerr(xprt);
1518 	}
1519 }
1520 
1521 static void
1522 handle_reply(fd, xprt)
1523 	int	fd;
1524 	SVCXPRT *xprt;
1525 {
1526 	XDR		reply_xdrs;
1527 	struct rpc_msg	reply_msg;
1528 	struct rpc_err	reply_error;
1529 	char		*buffer;
1530 	struct finfo	*fi = NULL;
1531 	int		inlen, pos, len, res, i;
1532 	struct r_rmtcall_args a;
1533 	struct t_unitdata	*tr_data = NULL, *tu_data;
1534 	struct netconfig	*nconf = NULL;
1535 	char *uaddr = NULL;
1536 
1537 	nconf = rpcbind_get_conf(xprt->xp_netid);
1538 	if (nconf == NULL) {
1539 #ifdef SVC_RUN_DEBUG
1540 		if (debugging)
1541 			fprintf(stderr, "handle_reply:  null xp_netid\n");
1542 #endif
1543 		goto done;
1544 	}
1545 	/*
1546 	 * If this fd is not active on the forward list, ignore it
1547 	 * If the svc_pollfd structure has multiple settings
1548 	 * of the same fd, then it will enter handle_reply() for the first one,
1549 	 * set FINFO_ACTIVE false and then get another call to handle_reply()
1550 	 * with the same, now inactive, fd.
1551 	 */
1552 
1553 	for (i = 0; i < NFORWARD; i++) {
1554 		if ((FINFO[i].forward_fd == fd) &&
1555 			(FINFO[i].flag & FINFO_ACTIVE))
1556 				break;
1557 	}
1558 
1559 	if (i == NFORWARD) {
1560 #ifdef  SVC_RUN_DEBUG
1561 		if (debugging) {
1562 			fprintf(stderr, "Unsolicited message on rmtcall fd\n");
1563 		}
1564 #endif
1565 		return;
1566 	}
1567 
1568 	reply_msg.rm_xid = 0;  /* for easier error handling */
1569 	tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA,
1570 						T_ADDR | T_UDATA);
1571 	if (tr_data == (struct t_unitdata *)NULL) {
1572 		if (debugging)
1573 			fprintf(stderr,
1574 			"handle_reply:  t_alloc T_UNITDATA failed\n");
1575 		goto done;
1576 	}
1577 	do {
1578 		int	moreflag;
1579 
1580 		moreflag = 0;
1581 		if (errno == EINTR)
1582 			errno = 0;
1583 		res = t_rcvudata(fd, tr_data, &moreflag);
1584 		if (moreflag & T_MORE) {
1585 			/* Drop this packet - we have no more space. */
1586 			if (debugging)
1587 				fprintf(stderr,
1588 			"handle_reply:  recvd packet with T_MORE flag set\n");
1589 			goto done;
1590 		}
1591 	} while (res < 0 && (t_errno == TSYSERR && errno == EINTR));
1592 	if (res < 0) {
1593 		if (t_errno == TLOOK) {
1594 			if (debugging)
1595 				fprintf(stderr,
1596 	"handle_reply:  t_rcvudata returned %d, t_errno TLOOK\n", res);
1597 			(void) t_rcvuderr(fd, (struct t_uderr *)NULL);
1598 		}
1599 
1600 		if (debugging)
1601 			fprintf(stderr,
1602 	"handle_reply:  t_rcvudata returned %d, t_errno %d, errno %d\n",
1603 				res, t_errno, errno);
1604 
1605 		goto done;
1606 	}
1607 
1608 	inlen = tr_data->udata.len;
1609 	uaddr = taddr2uaddr(nconf, &tr_data->addr);
1610 	if (uaddr == NULL)
1611 		goto done;
1612 
1613 #ifdef	DEBUG_MORE
1614 	if (debugging)
1615 		fprintf(stderr,
1616 		"handle_reply:  t_rcvudata received %d-byte packet from %s\n",
1617 		inlen, uaddr);
1618 #endif
1619 	buffer = tr_data->udata.buf;
1620 	if (buffer == (char *)NULL) {
1621 		goto done;
1622 	}
1623 	reply_msg.acpted_rply.ar_verf = _null_auth;
1624 	reply_msg.acpted_rply.ar_results.where = 0;
1625 	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
1626 
1627 	xdrmem_create(&reply_xdrs, buffer, (uint_t)inlen, XDR_DECODE);
1628 	if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
1629 		if (debugging)
1630 			(void) fprintf(stderr,
1631 				"handle_reply:  xdr_replymsg failed\n");
1632 		goto done;
1633 	}
1634 	fi = forward_find((ulong_t)reply_msg.rm_xid, uaddr);
1635 	if (fi == NULL)
1636 		goto done;
1637 #ifdef	SVC_RUN_DEBUG
1638 	if (debugging) {
1639 		fprintf(stderr, "handle_reply:  reply xid: %d fi addr: %x\n",
1640 			reply_msg.rm_xid, fi);
1641 	}
1642 #endif
1643 	__seterr_reply(&reply_msg, &reply_error);
1644 	if (reply_error.re_status != RPC_SUCCESS) {
1645 		if (debugging)
1646 			(void) fprintf(stderr, "handle_reply:  %s\n",
1647 				clnt_sperrno(reply_error.re_status));
1648 		send_svcsyserr(xprt, fi);
1649 		goto done;
1650 	}
1651 	pos = XDR_GETPOS(&reply_xdrs);
1652 	len = inlen - pos;
1653 	a.rmt_args.args = &buffer[pos];
1654 	a.rmt_args.arglen = len;
1655 	a.rmt_uaddr = fi->uaddr;
1656 	a.rmt_localvers = fi->versnum;
1657 
1658 	xprt_set_caller(xprt, fi);
1659 	/* XXX hack */
1660 	tu_data =  &(getbogus_data(xprt)->su_tudata);
1661 
1662 	tu_data->addr = xprt->xp_rtaddr;
1663 #ifdef	SVC_RUN_DEBUG
1664 	if (uaddr)
1665 		free((void *) uaddr);
1666 	uaddr = taddr2uaddr(nconf, svc_getrpccaller(xprt));
1667 	if (debugging) {
1668 		fprintf(stderr, "handle_reply:  forwarding address %s to %s\n",
1669 			a.rmt_uaddr, uaddr ? uaddr : "unknown");
1670 	}
1671 #endif
1672 	svc_sendreply(xprt, (xdrproc_t)xdr_rmtcall_result, (char *)&a);
1673 done:
1674 	if (uaddr)
1675 		free((void *) uaddr);
1676 	if (tr_data)
1677 		t_free((char *)tr_data, T_UNITDATA);
1678 	if ((fi == NULL) || (reply_msg.rm_xid == 0)) {
1679 #ifdef	SVC_RUN_DEBUG
1680 	if (debugging) {
1681 		fprintf(stderr, "handle_reply:  NULL xid on exit!\n");
1682 	}
1683 #endif
1684 	} else
1685 		(void) free_slot_by_xid((ulong_t)reply_msg.rm_xid, fi->uaddr);
1686 }
1687 
1688 static void
1689 find_versions(prog, netid, lowvp, highvp)
1690 	ulong_t prog;	/* Program Number */
1691 	char *netid;	/* Transport Provider token */
1692 	ulong_t *lowvp;  /* Low version number */
1693 	ulong_t *highvp; /* High version number */
1694 {
1695 	register rpcblist_ptr rbl;
1696 	int lowv = 0;
1697 	int highv = 0;
1698 
1699 	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1700 		if ((rbl->rpcb_map.r_prog != prog) ||
1701 		    ((rbl->rpcb_map.r_netid != NULL) &&
1702 			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
1703 			continue;
1704 		if (lowv == 0) {
1705 			highv = rbl->rpcb_map.r_vers;
1706 			lowv = highv;
1707 		} else if (rbl->rpcb_map.r_vers < lowv) {
1708 			lowv = rbl->rpcb_map.r_vers;
1709 		} else if (rbl->rpcb_map.r_vers > highv) {
1710 			highv = rbl->rpcb_map.r_vers;
1711 		}
1712 	}
1713 	*lowvp = lowv;
1714 	*highvp = highv;
1715 }
1716 
1717 /*
1718  * returns the item with the given program, version number and netid.
1719  * If that version number is not found, it returns the item with that
1720  * program number, so that address is now returned to the caller. The
1721  * caller when makes a call to this program, version number, the call
1722  * will fail and it will return with PROGVERS_MISMATCH. The user can
1723  * then determine the highest and the lowest version number for this
1724  * program using clnt_geterr() and use those program version numbers.
1725  *
1726  * Returns the RPCBLIST for the given prog, vers and netid
1727  */
1728 static rpcblist_ptr
1729 find_service(prog, vers, netid)
1730 	ulong_t prog;	/* Program Number */
1731 	ulong_t vers;	/* Version Number */
1732 	char *netid;	/* Transport Provider token */
1733 {
1734 	register rpcblist_ptr hit = NULL;
1735 	register rpcblist_ptr rbl;
1736 
1737 	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
1738 		if ((rbl->rpcb_map.r_prog != prog) ||
1739 		    ((rbl->rpcb_map.r_netid != NULL) &&
1740 			(strcasecmp(rbl->rpcb_map.r_netid, netid) != 0)))
1741 			continue;
1742 		hit = rbl;
1743 		if (rbl->rpcb_map.r_vers == vers)
1744 			break;
1745 	}
1746 	return (hit);
1747 }
1748 
1749 /*
1750  * If the caller is from our zone and we know
1751  * who it is, we return the uid.
1752  */
1753 uid_t
1754 rpcb_caller_uid(SVCXPRT *transp)
1755 {
1756 	ucred_t *uc = alloca(ucred_size());
1757 	static zoneid_t myzone = MIN_ZONEID - 1;
1758 	uid_t uid;
1759 
1760 	if (myzone == MIN_ZONEID - 1)
1761 		myzone = getzoneid();
1762 
1763 	if (svc_getcallerucred(transp, &uc) != 0 ||
1764 	    (ucred_getzoneid(uc)) != myzone) {
1765 		return (-1);
1766 	} else {
1767 		return (ucred_geteuid(uc));
1768 	}
1769 }
1770 
1771 /*
1772  * Copies the name associated with the uid of the caller and returns
1773  * a pointer to it.  Similar to getwd().
1774  */
1775 char *
1776 getowner(transp, owner)
1777 	SVCXPRT *transp;
1778 	char *owner;
1779 {
1780 	uid_t uid = rpcb_caller_uid(transp);
1781 
1782 	switch (uid) {
1783 	case -1:
1784 		return (strcpy(owner, "unknown"));
1785 	case 0:
1786 		return (strcpy(owner, "superuser"));
1787 	default:
1788 		(void) sprintf(owner, "%u", uid);
1789 		return (owner);
1790 	}
1791 }
1792 
1793 #ifdef PORTMAP
1794 /*
1795  * Add this to the pmap list only if it is UDP or TCP.
1796  */
1797 static int
1798 add_pmaplist(arg)
1799 	RPCB *arg;
1800 {
1801 	pmap pmap;
1802 	pmaplist *pml;
1803 	int h1, h2, h3, h4, p1, p2;
1804 
1805 	if (strcmp(arg->r_netid, udptrans) == 0) {
1806 		/* It is UDP! */
1807 		pmap.pm_prot = IPPROTO_UDP;
1808 	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
1809 		/* It is TCP */
1810 		pmap.pm_prot = IPPROTO_TCP;
1811 	} else
1812 		/* Not a IP protocol */
1813 		return (0);
1814 
1815 	/* interpret the universal address for TCP/IP */
1816 	if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
1817 		&h1, &h2, &h3, &h4, &p1, &p2) != 6)
1818 		return (0);
1819 	pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
1820 	pmap.pm_prog = arg->r_prog;
1821 	pmap.pm_vers = arg->r_vers;
1822 	/*
1823 	 * add to END of list
1824 	 */
1825 	pml = (pmaplist *) malloc((uint_t)sizeof (pmaplist));
1826 	if (pml == NULL) {
1827 		(void) syslog(LOG_ERR, "rpcbind: no memory!\n");
1828 		return (1);
1829 	}
1830 	pml->pml_map = pmap;
1831 	pml->pml_next = NULL;
1832 	if (list_pml == NULL) {
1833 		list_pml = pml;
1834 	} else {
1835 		pmaplist *fnd;
1836 
1837 		/* Attach to the end of the list */
1838 		for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
1839 			;
1840 		fnd->pml_next = pml;
1841 	}
1842 	return (0);
1843 }
1844 
1845 /*
1846  * Delete this from the pmap list only if it is UDP or TCP.
1847  */
1848 int
1849 del_pmaplist(RPCB *arg)
1850 {
1851 	register pmaplist *pml;
1852 	pmaplist *prevpml, *fnd;
1853 	long prot;
1854 
1855 	if (strcmp(arg->r_netid, udptrans) == 0) {
1856 		/* It is UDP! */
1857 		prot = IPPROTO_UDP;
1858 	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
1859 		/* It is TCP */
1860 		prot = IPPROTO_TCP;
1861 	} else if (arg->r_netid[0] == NULL) {
1862 		prot = 0;	/* Remove all occurrences */
1863 	} else {
1864 		/* Not a IP protocol */
1865 		return (0);
1866 	}
1867 	for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
1868 		if ((pml->pml_map.pm_prog != arg->r_prog) ||
1869 			(pml->pml_map.pm_vers != arg->r_vers) ||
1870 			(prot && (pml->pml_map.pm_prot != prot))) {
1871 			/* both pml & prevpml move forwards */
1872 			prevpml = pml;
1873 			pml = pml->pml_next;
1874 			continue;
1875 		}
1876 		/* found it; pml moves forward, prevpml stays */
1877 		fnd = pml;
1878 		pml = pml->pml_next;
1879 		if (prevpml == NULL)
1880 			list_pml = pml;
1881 		else
1882 			prevpml->pml_next = pml;
1883 		free((void *) fnd);
1884 	}
1885 	return (0);
1886 }
1887 #endif /* PORTMAP */
1888