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