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