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