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