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