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