17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53582b7c1Sgt  * Common Development and Distribution License (the "License").
63582b7c1Sgt  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2236e852a1SRaja Andra  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
258f6d9daeSMarcel Telka /*
268f6d9daeSMarcel Telka  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
27*b1cdc720SAlex Wilson  * Copyright 2017 Joyent Inc
288f6d9daeSMarcel Telka  */
297c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
307c478bd9Sstevel@tonic-gate /* All Rights Reserved */
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
337c478bd9Sstevel@tonic-gate  * The Regents of the University of California
347c478bd9Sstevel@tonic-gate  * All Rights Reserved
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
377c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
387c478bd9Sstevel@tonic-gate  * contributors.
397c478bd9Sstevel@tonic-gate  */
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /*
427c478bd9Sstevel@tonic-gate  * rpcb_svc_com.c
437c478bd9Sstevel@tonic-gate  * The commom server procedure for the rpcbind.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <stdio.h>
477c478bd9Sstevel@tonic-gate #include <sys/types.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <unistd.h>
507c478bd9Sstevel@tonic-gate #include <stdlib.h>
517c478bd9Sstevel@tonic-gate #include <string.h>
527c478bd9Sstevel@tonic-gate #include <strings.h>
537c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
547c478bd9Sstevel@tonic-gate #include <rpc/rpcb_prot.h>
55f48205beScasper #include <rpcsvc/svc_dg_priv.h>
567c478bd9Sstevel@tonic-gate #include <netconfig.h>
577c478bd9Sstevel@tonic-gate #include <sys/param.h>
587c478bd9Sstevel@tonic-gate #include <errno.h>
597c478bd9Sstevel@tonic-gate #include <zone.h>
607c478bd9Sstevel@tonic-gate #include <sys/poll.h>
617c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
627c478bd9Sstevel@tonic-gate #ifdef PORTMAP
637c478bd9Sstevel@tonic-gate #include <netinet/in.h>
647c478bd9Sstevel@tonic-gate #include <rpc/pmap_prot.h>
658f6d9daeSMarcel Telka #else
668f6d9daeSMarcel Telka #define	PMAPVERS	2
677c478bd9Sstevel@tonic-gate #endif /* PORTMAP */
687c478bd9Sstevel@tonic-gate #include <syslog.h>
697c478bd9Sstevel@tonic-gate #include <netdir.h>
707c478bd9Sstevel@tonic-gate #include <ucred.h>
717c478bd9Sstevel@tonic-gate #include <alloca.h>
727c478bd9Sstevel@tonic-gate #include <rpcsvc/yp_prot.h>
737c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
747c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h>
757c478bd9Sstevel@tonic-gate #include <rpcsvc/mount.h>
767c478bd9Sstevel@tonic-gate #include <nfs/nfs_acl.h>
777c478bd9Sstevel@tonic-gate #include <rpc/key_prot.h>
787c478bd9Sstevel@tonic-gate #include <rpcsvc/yp_prot.h>
797c478bd9Sstevel@tonic-gate #include <rpcsvc/rquota.h>
807c478bd9Sstevel@tonic-gate #include <rpcsvc/yppasswd.h>
817c478bd9Sstevel@tonic-gate #include <rpcsvc/ypupd.h>
828f6d9daeSMarcel Telka #include <assert.h>
838f6d9daeSMarcel Telka #include <synch.h>
847c478bd9Sstevel@tonic-gate #include "rpcbind.h"
85*b1cdc720SAlex Wilson #include <sys/debug.h>
867c478bd9Sstevel@tonic-gate 
878f6d9daeSMarcel Telka static struct finfo *forward_register(ulong_t, struct netbuf *, int, char *);
888f6d9daeSMarcel Telka static void forward_destroy(struct finfo *);
898f6d9daeSMarcel Telka static void handle_reply(svc_input_id_t, int, unsigned int, void *);
908f6d9daeSMarcel Telka static int netbufcmp(struct netbuf *, struct netbuf *);
918f6d9daeSMarcel Telka static void netbuffree(struct netbuf *);
928f6d9daeSMarcel Telka static struct netbuf *netbufdup(struct netbuf *);
938f6d9daeSMarcel Telka static void find_versions(rpcprog_t, char *, rpcvers_t *, rpcvers_t *);
948f6d9daeSMarcel Telka static rpcblist_ptr find_service(ulong_t, ulong_t, char *);
958f6d9daeSMarcel Telka #ifdef PORTMAP
968f6d9daeSMarcel Telka static int add_pmaplist(RPCB *);
978f6d9daeSMarcel Telka #endif
988f6d9daeSMarcel Telka 
998f6d9daeSMarcel Telka zoneid_t myzone;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * Set a mapping of program, version, netid
1037c478bd9Sstevel@tonic-gate  */
1048f6d9daeSMarcel Telka bool_t
rpcbproc_set_com(RPCB * regp,bool_t * result,struct svc_req * rqstp,int rpcbversnum)1058f6d9daeSMarcel Telka rpcbproc_set_com(RPCB *regp, bool_t *result, struct svc_req *rqstp,
1068f6d9daeSMarcel Telka     int rpcbversnum)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 	char owner[64];
1097c478bd9Sstevel@tonic-gate 
1108f6d9daeSMarcel Telka 	*result = map_set(regp, getowner(rqstp->rq_xprt, owner));
1118f6d9daeSMarcel Telka 
1128f6d9daeSMarcel Telka 	rpcbs_set(rpcbversnum - PMAPVERS, *result);
1138f6d9daeSMarcel Telka 
1148f6d9daeSMarcel Telka 	return (TRUE);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate bool_t
map_set(RPCB * regp,char * owner)1188f6d9daeSMarcel Telka map_set(RPCB *regp, char *owner)
1197c478bd9Sstevel@tonic-gate {
1208f6d9daeSMarcel Telka 	RPCB *a;
1217c478bd9Sstevel@tonic-gate 	rpcblist_ptr rbl, fnd;
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * check to see if already used
1257c478bd9Sstevel@tonic-gate 	 * find_service returns a hit even if
1267c478bd9Sstevel@tonic-gate 	 * the versions don't match, so check for it
1277c478bd9Sstevel@tonic-gate 	 */
1288f6d9daeSMarcel Telka 	(void) rw_wrlock(&list_rbl_lock);
1298f6d9daeSMarcel Telka #ifdef PORTMAP
1308f6d9daeSMarcel Telka 	(void) rw_wrlock(&list_pml_lock);
1318f6d9daeSMarcel Telka #endif /* PORTMAP */
1328f6d9daeSMarcel Telka 	fnd = find_service(regp->r_prog, regp->r_vers, regp->r_netid);
1338f6d9daeSMarcel Telka 	if (fnd && (fnd->rpcb_map.r_vers == regp->r_vers)) {
1348f6d9daeSMarcel Telka 		if (strcmp(fnd->rpcb_map.r_addr, regp->r_addr) == 0) {
1357c478bd9Sstevel@tonic-gate 			/*
1367c478bd9Sstevel@tonic-gate 			 * if these match then it is already
1377c478bd9Sstevel@tonic-gate 			 * registered so just say "OK".
1387c478bd9Sstevel@tonic-gate 			 */
1398f6d9daeSMarcel Telka #ifdef PORTMAP
1408f6d9daeSMarcel Telka 			(void) rw_unlock(&list_pml_lock);
1418f6d9daeSMarcel Telka #endif /* PORTMAP */
1428f6d9daeSMarcel Telka 			(void) rw_unlock(&list_rbl_lock);
1437c478bd9Sstevel@tonic-gate 			return (TRUE);
1448f6d9daeSMarcel Telka 		} else {
1457c478bd9Sstevel@tonic-gate 			/*
1467c478bd9Sstevel@tonic-gate 			 * Check if server is up.  If so, return FALSE.
1477c478bd9Sstevel@tonic-gate 			 * If not, cleanup old registrations for the
1487c478bd9Sstevel@tonic-gate 			 * program and register the new server.
1497c478bd9Sstevel@tonic-gate 			 */
1507c478bd9Sstevel@tonic-gate 			if (is_bound(fnd->rpcb_map.r_netid,
1518f6d9daeSMarcel Telka 			    fnd->rpcb_map.r_addr)) {
1528f6d9daeSMarcel Telka #ifdef PORTMAP
1538f6d9daeSMarcel Telka 				(void) rw_unlock(&list_pml_lock);
1548f6d9daeSMarcel Telka #endif /* PORTMAP */
1558f6d9daeSMarcel Telka 				(void) rw_unlock(&list_rbl_lock);
1567c478bd9Sstevel@tonic-gate 				return (FALSE);
1578f6d9daeSMarcel Telka 			}
1588f6d9daeSMarcel Telka 
1598f6d9daeSMarcel Telka 			delete_prog(regp->r_prog);
1607c478bd9Sstevel@tonic-gate 			fnd = NULL;
1617c478bd9Sstevel@tonic-gate 		}
1627c478bd9Sstevel@tonic-gate 	}
1638f6d9daeSMarcel Telka #ifdef PORTMAP
1648f6d9daeSMarcel Telka 	(void) rw_unlock(&list_pml_lock);
1658f6d9daeSMarcel Telka #endif /* PORTMAP */
1668f6d9daeSMarcel Telka 
1677c478bd9Sstevel@tonic-gate 	/*
1687c478bd9Sstevel@tonic-gate 	 * add to the end of the list
1697c478bd9Sstevel@tonic-gate 	 */
1708f6d9daeSMarcel Telka 	rbl = malloc(sizeof (RPCBLIST));
1718f6d9daeSMarcel Telka 	if (rbl == NULL) {
1728f6d9daeSMarcel Telka 		(void) rw_unlock(&list_rbl_lock);
1737c478bd9Sstevel@tonic-gate 		return (FALSE);
1747c478bd9Sstevel@tonic-gate 	}
1758f6d9daeSMarcel Telka 	a = &rbl->rpcb_map;
1768f6d9daeSMarcel Telka 	a->r_prog = regp->r_prog;
1778f6d9daeSMarcel Telka 	a->r_vers = regp->r_vers;
1788f6d9daeSMarcel Telka 	a->r_netid = strdup(regp->r_netid);
1798f6d9daeSMarcel Telka 	a->r_addr = strdup(regp->r_addr);
1807c478bd9Sstevel@tonic-gate 	a->r_owner = strdup(owner);
1817c478bd9Sstevel@tonic-gate 	if (a->r_addr == NULL || a->r_netid == NULL|| a->r_owner == NULL) {
1828f6d9daeSMarcel Telka 		(void) rw_unlock(&list_rbl_lock);
1837c478bd9Sstevel@tonic-gate 		delete_rbl(rbl);
1847c478bd9Sstevel@tonic-gate 		return (FALSE);
1857c478bd9Sstevel@tonic-gate 	}
1868f6d9daeSMarcel Telka 	rbl->rpcb_next = NULL;
1877c478bd9Sstevel@tonic-gate 	if (list_rbl == NULL) {
1887c478bd9Sstevel@tonic-gate 		list_rbl = rbl;
1897c478bd9Sstevel@tonic-gate 	} else {
1908f6d9daeSMarcel Telka 		for (fnd = list_rbl; fnd->rpcb_next; fnd = fnd->rpcb_next)
1917c478bd9Sstevel@tonic-gate 			;
1927c478bd9Sstevel@tonic-gate 		fnd->rpcb_next = rbl;
1937c478bd9Sstevel@tonic-gate 	}
1948f6d9daeSMarcel Telka 
1957c478bd9Sstevel@tonic-gate #ifdef PORTMAP
1967c478bd9Sstevel@tonic-gate 	(void) add_pmaplist(regp);
1977c478bd9Sstevel@tonic-gate #endif
1988f6d9daeSMarcel Telka 	(void) rw_unlock(&list_rbl_lock);
1997c478bd9Sstevel@tonic-gate 	return (TRUE);
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /*
2037c478bd9Sstevel@tonic-gate  * Unset a mapping of program, version, netid
2047c478bd9Sstevel@tonic-gate  */
2058f6d9daeSMarcel Telka bool_t
rpcbproc_unset_com(RPCB * regp,bool_t * result,struct svc_req * rqstp,int rpcbversnum)2068f6d9daeSMarcel Telka rpcbproc_unset_com(RPCB *regp, bool_t *result, struct svc_req *rqstp,
2078f6d9daeSMarcel Telka     int rpcbversnum)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	char owner[64];
2107c478bd9Sstevel@tonic-gate 
2118f6d9daeSMarcel Telka 	*result = map_unset(regp, getowner(rqstp->rq_xprt, owner));
2128f6d9daeSMarcel Telka 
2138f6d9daeSMarcel Telka 	rpcbs_unset(rpcbversnum - PMAPVERS, *result);
2148f6d9daeSMarcel Telka 
2158f6d9daeSMarcel Telka 	return (TRUE);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate bool_t
map_unset(RPCB * regp,char * owner)2198f6d9daeSMarcel Telka map_unset(RPCB *regp, char *owner)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate #ifdef PORTMAP
2227c478bd9Sstevel@tonic-gate 	int ans = 0;
2237c478bd9Sstevel@tonic-gate #endif
2247c478bd9Sstevel@tonic-gate 	rpcblist_ptr rbl, next, prev = NULL;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	if (owner == NULL)
2277c478bd9Sstevel@tonic-gate 		return (0);
2287c478bd9Sstevel@tonic-gate 
2298f6d9daeSMarcel Telka 	(void) rw_wrlock(&list_rbl_lock);
2307c478bd9Sstevel@tonic-gate 	for (rbl = list_rbl; rbl != NULL; rbl = next) {
2317c478bd9Sstevel@tonic-gate 		next = rbl->rpcb_next;
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 		if ((rbl->rpcb_map.r_prog != regp->r_prog) ||
2347c478bd9Sstevel@tonic-gate 		    (rbl->rpcb_map.r_vers != regp->r_vers) ||
2357c478bd9Sstevel@tonic-gate 		    (regp->r_netid[0] && strcasecmp(regp->r_netid,
2368f6d9daeSMarcel Telka 		    rbl->rpcb_map.r_netid))) {
2377c478bd9Sstevel@tonic-gate 			/* prev moves forwards */
2387c478bd9Sstevel@tonic-gate 			prev = rbl;
2397c478bd9Sstevel@tonic-gate 			continue;
2407c478bd9Sstevel@tonic-gate 		}
2418f6d9daeSMarcel Telka 
2427c478bd9Sstevel@tonic-gate 		/*
2437c478bd9Sstevel@tonic-gate 		 * Check whether appropriate uid. Unset only
2447c478bd9Sstevel@tonic-gate 		 * if superuser or the owner itself.
2457c478bd9Sstevel@tonic-gate 		 */
2467c478bd9Sstevel@tonic-gate 		if (strcmp(owner, "superuser") &&
2478f6d9daeSMarcel Telka 		    strcmp(rbl->rpcb_map.r_owner, owner)) {
2488f6d9daeSMarcel Telka 			(void) rw_unlock(&list_rbl_lock);
2497c478bd9Sstevel@tonic-gate 			return (0);
2508f6d9daeSMarcel Telka 		}
2518f6d9daeSMarcel Telka 
2527c478bd9Sstevel@tonic-gate 		/* prev stays */
2537c478bd9Sstevel@tonic-gate #ifdef PORTMAP
2547c478bd9Sstevel@tonic-gate 		ans = 1;
2557c478bd9Sstevel@tonic-gate #endif
2567c478bd9Sstevel@tonic-gate 		delete_rbl(rbl);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 		if (prev == NULL)
2597c478bd9Sstevel@tonic-gate 			list_rbl = next;
2607c478bd9Sstevel@tonic-gate 		else
2617c478bd9Sstevel@tonic-gate 			prev->rpcb_next = next;
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate #ifdef PORTMAP
2648f6d9daeSMarcel Telka 	if (ans != 0) {
2658f6d9daeSMarcel Telka 		(void) rw_wrlock(&list_pml_lock);
2667c478bd9Sstevel@tonic-gate 		(void) del_pmaplist(regp);
2678f6d9daeSMarcel Telka 		(void) rw_unlock(&list_pml_lock);
2688f6d9daeSMarcel Telka 	}
2697c478bd9Sstevel@tonic-gate #endif
2708f6d9daeSMarcel Telka 	(void) rw_unlock(&list_rbl_lock);
2718f6d9daeSMarcel Telka 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * We return 1 either when the entry was not there or it
2747c478bd9Sstevel@tonic-gate 	 * was able to unset it.  It can come to this point only if
275da6c28aaSamw 	 * at least one of the conditions is true.
2767c478bd9Sstevel@tonic-gate 	 */
2777c478bd9Sstevel@tonic-gate 	return (1);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate 
2803582b7c1Sgt void
delete_rbl(rpcblist_ptr rbl)2813582b7c1Sgt delete_rbl(rpcblist_ptr rbl)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate 	free(rbl->rpcb_map.r_addr);
2847c478bd9Sstevel@tonic-gate 	free(rbl->rpcb_map.r_netid);
2857c478bd9Sstevel@tonic-gate 	free(rbl->rpcb_map.r_owner);
2867c478bd9Sstevel@tonic-gate 	free(rbl);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate void
delete_prog(rpcprog_t prog)2908f6d9daeSMarcel Telka delete_prog(rpcprog_t prog)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	rpcblist_ptr rbl, next, prev = NULL;
2937c478bd9Sstevel@tonic-gate 
2948f6d9daeSMarcel Telka 	assert(RW_WRITE_HELD(&list_rbl_lock));
2958f6d9daeSMarcel Telka 
2967c478bd9Sstevel@tonic-gate 	for (rbl = list_rbl; rbl != NULL; rbl = next) {
2977c478bd9Sstevel@tonic-gate 		next = rbl->rpcb_next;
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 		if (rbl->rpcb_map.r_prog != prog ||
3007c478bd9Sstevel@tonic-gate 		    is_bound(rbl->rpcb_map.r_netid, rbl->rpcb_map.r_addr)) {
3017c478bd9Sstevel@tonic-gate 			prev = rbl;
3027c478bd9Sstevel@tonic-gate 			continue;
3037c478bd9Sstevel@tonic-gate 		}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate #ifdef PORTMAP
3067c478bd9Sstevel@tonic-gate 		(void) del_pmaplist(&rbl->rpcb_map);
3077c478bd9Sstevel@tonic-gate #endif
3087c478bd9Sstevel@tonic-gate 		delete_rbl(rbl);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 		if (prev == NULL)
3117c478bd9Sstevel@tonic-gate 			list_rbl = next;
3127c478bd9Sstevel@tonic-gate 		else
3137c478bd9Sstevel@tonic-gate 			prev->rpcb_next = next;
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3178f6d9daeSMarcel Telka /*
3188f6d9daeSMarcel Telka  * Lookup the mapping for a program, version and return its
3198f6d9daeSMarcel Telka  * address. Assuming that the caller wants the address of the
3208f6d9daeSMarcel Telka  * server running on the transport on which the request came.
3218f6d9daeSMarcel Telka  *
3228f6d9daeSMarcel Telka  * For RPCBPROC_GETVERSADDR it will return a service with the exact version
3238f6d9daeSMarcel Telka  * number only.
3248f6d9daeSMarcel Telka  *
3258f6d9daeSMarcel Telka  * Otherwise, even if a service with a different version number is available,
3268f6d9daeSMarcel Telka  * it will return that address.  The client should check with an
3278f6d9daeSMarcel Telka  * clnt_call to verify whether the service is the one that is desired.
3288f6d9daeSMarcel Telka  *
3298f6d9daeSMarcel Telka  * We also try to resolve the universal address in terms of
3308f6d9daeSMarcel Telka  * address of the caller.
3318f6d9daeSMarcel Telka  */
3328f6d9daeSMarcel Telka bool_t
rpcbproc_getaddr_com(RPCB * regp,char ** result,struct svc_req * rqstp,ulong_t rpcbversnum)3338f6d9daeSMarcel Telka rpcbproc_getaddr_com(RPCB *regp, char **result, struct svc_req *rqstp,
3348f6d9daeSMarcel Telka     ulong_t rpcbversnum)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	char *saddr = NULL;
3377c478bd9Sstevel@tonic-gate 	rpcblist_ptr fnd;
3387c478bd9Sstevel@tonic-gate 	struct netconfig *trans_conf;	/* transport netconfig */
3398f6d9daeSMarcel Telka 	SVCXPRT *transp = rqstp->rq_xprt;
3408f6d9daeSMarcel Telka 	int verstype = rqstp->rq_proc == RPCBPROC_GETVERSADDR ? RPCB_ONEVERS :
3418f6d9daeSMarcel Telka 	    RPCB_ALLVERS;
3428f6d9daeSMarcel Telka 	bool_t pml_locked = FALSE;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	/*
3457c478bd9Sstevel@tonic-gate 	 * There is a potential window at startup during which rpcbind
3467c478bd9Sstevel@tonic-gate 	 * service has been established over IPv6 but not over IPv4.  If an
3477c478bd9Sstevel@tonic-gate 	 * IPv4 request comes in during that window, the IP code will map
3487c478bd9Sstevel@tonic-gate 	 * it into IPv6.  We could patch up the request so that it looks
3497c478bd9Sstevel@tonic-gate 	 * like IPv4 (so that rpcbind returns an IPv4 uaddr to the caller),
3507c478bd9Sstevel@tonic-gate 	 * but that requires some non-trivial code and it's hard to test.
3517c478bd9Sstevel@tonic-gate 	 * Instead, drop the request on the floor and force the caller to
3527c478bd9Sstevel@tonic-gate 	 * retransmit.  By the time rpcbind sees the retransmission, IPv4
3537c478bd9Sstevel@tonic-gate 	 * service should be in place and it should see the request as
3547c478bd9Sstevel@tonic-gate 	 * IPv4, as desired.
3557c478bd9Sstevel@tonic-gate 	 */
3567c478bd9Sstevel@tonic-gate 	trans_conf = rpcbind_get_conf(transp->xp_netid);
3577c478bd9Sstevel@tonic-gate 	if (strcmp(trans_conf->nc_protofmly, NC_INET6) == 0) {
3587c478bd9Sstevel@tonic-gate 		struct sockaddr_in6 *rmtaddr;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		rmtaddr = (struct sockaddr_in6 *)transp->xp_rtaddr.buf;
3617c478bd9Sstevel@tonic-gate 		if (IN6_IS_ADDR_V4MAPPED(&rmtaddr->sin6_addr)) {
3627c478bd9Sstevel@tonic-gate 			syslog(LOG_DEBUG,
3637c478bd9Sstevel@tonic-gate 			    "IPv4 GETADDR request mapped to IPv6: ignoring");
3648f6d9daeSMarcel Telka 			*result = NULL;
3658f6d9daeSMarcel Telka 			return (FALSE);
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3698f6d9daeSMarcel Telka 	(void) rw_rdlock(&list_rbl_lock);
3708f6d9daeSMarcel Telka retry:
3717c478bd9Sstevel@tonic-gate 	fnd = find_service(regp->r_prog, regp->r_vers, transp->xp_netid);
3727c478bd9Sstevel@tonic-gate 	if (fnd && ((verstype == RPCB_ALLVERS) ||
3738f6d9daeSMarcel Telka 	    (regp->r_vers == fnd->rpcb_map.r_vers))) {
3747c478bd9Sstevel@tonic-gate 		if (*(regp->r_addr) != '\0') {  /* may contain a hint about */
3757c478bd9Sstevel@tonic-gate 			saddr = regp->r_addr;   /* the interface that we    */
3767c478bd9Sstevel@tonic-gate 		}				/* should use */
3778f6d9daeSMarcel Telka 		if (!(*result = mergeaddr(transp, transp->xp_netid,
3788f6d9daeSMarcel Telka 		    fnd->rpcb_map.r_addr, saddr))) {
3797c478bd9Sstevel@tonic-gate 			/* Try whatever we have */
3808f6d9daeSMarcel Telka 			*result = strdup(fnd->rpcb_map.r_addr);
3818f6d9daeSMarcel Telka 		} else if (!(*result)[0]) {
3828f6d9daeSMarcel Telka 			if (!pml_locked) {
3838f6d9daeSMarcel Telka 				(void) rw_unlock(&list_rbl_lock);
3848f6d9daeSMarcel Telka 				(void) rw_wrlock(&list_rbl_lock);
3858f6d9daeSMarcel Telka #ifdef PORTMAP
3868f6d9daeSMarcel Telka 				(void) rw_wrlock(&list_pml_lock);
3878f6d9daeSMarcel Telka #endif /* PORTMAP */
3888f6d9daeSMarcel Telka 				pml_locked = TRUE;
3898f6d9daeSMarcel Telka 				goto retry;
3908f6d9daeSMarcel Telka 			}
3917c478bd9Sstevel@tonic-gate 			/*
3927c478bd9Sstevel@tonic-gate 			 * The server died.  Unset all versions of this prog.
3937c478bd9Sstevel@tonic-gate 			 */
3947c478bd9Sstevel@tonic-gate 			delete_prog(regp->r_prog);
3958f6d9daeSMarcel Telka 			*result = NULL;
3967c478bd9Sstevel@tonic-gate 		}
3977c478bd9Sstevel@tonic-gate 	} else {
3988f6d9daeSMarcel Telka 		*result = NULL;
3997c478bd9Sstevel@tonic-gate 	}
4008f6d9daeSMarcel Telka #ifdef PORTMAP
4018f6d9daeSMarcel Telka 	if (pml_locked)
4028f6d9daeSMarcel Telka 		(void) rw_unlock(&list_pml_lock);
4038f6d9daeSMarcel Telka #endif /* PORTMAP */
4048f6d9daeSMarcel Telka 	(void) rw_unlock(&list_rbl_lock);
4058f6d9daeSMarcel Telka 
4068f6d9daeSMarcel Telka 	rpcbs_getaddr(rpcbversnum - PMAPVERS, regp->r_prog, regp->r_vers,
4078f6d9daeSMarcel Telka 	    transp->xp_netid, *result);
4088f6d9daeSMarcel Telka 	return (TRUE);
4097c478bd9Sstevel@tonic-gate }
4107c478bd9Sstevel@tonic-gate 
4118f6d9daeSMarcel Telka /* ARGSUSED */
4128f6d9daeSMarcel Telka bool_t
rpcbproc_dump_com(void * argp,rpcblist_ptr ** result)4138f6d9daeSMarcel Telka rpcbproc_dump_com(void *argp, rpcblist_ptr **result)
4147c478bd9Sstevel@tonic-gate {
4158f6d9daeSMarcel Telka 	/*
4168f6d9daeSMarcel Telka 	 * list_rbl_lock is unlocked in xdr_rpcblist_ptr_ptr()
4178f6d9daeSMarcel Telka 	 */
4188f6d9daeSMarcel Telka 	(void) rw_rdlock(&list_rbl_lock);
4198f6d9daeSMarcel Telka 	*result = &list_rbl;
4208f6d9daeSMarcel Telka 	return (TRUE);
4218f6d9daeSMarcel Telka }
4227c478bd9Sstevel@tonic-gate 
4238f6d9daeSMarcel Telka bool_t
xdr_rpcblist_ptr_ptr(XDR * xdrs,rpcblist_ptr ** objp)4248f6d9daeSMarcel Telka xdr_rpcblist_ptr_ptr(XDR *xdrs, rpcblist_ptr **objp)
4258f6d9daeSMarcel Telka {
4268f6d9daeSMarcel Telka 	if (xdrs->x_op == XDR_FREE) {
4278f6d9daeSMarcel Telka 		/*
4288f6d9daeSMarcel Telka 		 * list_rbl_lock is locked in rpcbproc_dump_com()
4298f6d9daeSMarcel Telka 		 */
4308f6d9daeSMarcel Telka 		rw_unlock(&list_rbl_lock);
4318f6d9daeSMarcel Telka 		return (TRUE);
4328f6d9daeSMarcel Telka 	}
4338f6d9daeSMarcel Telka 
4348f6d9daeSMarcel Telka 	return (xdr_rpcblist_ptr(xdrs, *objp));
4358f6d9daeSMarcel Telka }
4368f6d9daeSMarcel Telka 
4378f6d9daeSMarcel Telka /* ARGSUSED */
4388f6d9daeSMarcel Telka bool_t
rpcbproc_gettime_com(void * argp,ulong_t * result)4398f6d9daeSMarcel Telka rpcbproc_gettime_com(void *argp, ulong_t *result)
4408f6d9daeSMarcel Telka {
4418f6d9daeSMarcel Telka 	(void) time((time_t *)result);
4428f6d9daeSMarcel Telka 
4438f6d9daeSMarcel Telka 	return (TRUE);
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate /*
4477c478bd9Sstevel@tonic-gate  * Convert uaddr to taddr. Should be used only by
4487c478bd9Sstevel@tonic-gate  * local servers/clients. (kernel level stuff only)
4497c478bd9Sstevel@tonic-gate  */
4508f6d9daeSMarcel Telka bool_t
rpcbproc_uaddr2taddr_com(char ** uaddrp,struct netbuf * result,struct svc_req * rqstp)4518f6d9daeSMarcel Telka rpcbproc_uaddr2taddr_com(char **uaddrp, struct netbuf *result,
4528f6d9daeSMarcel Telka     struct svc_req *rqstp)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
4558f6d9daeSMarcel Telka 	struct netbuf *taddr;
4567c478bd9Sstevel@tonic-gate 
4578f6d9daeSMarcel Telka 	if (((nconf = rpcbind_get_conf(rqstp->rq_xprt->xp_netid)) == NULL) ||
4587c478bd9Sstevel@tonic-gate 	    ((taddr = uaddr2taddr(nconf, *uaddrp)) == NULL)) {
4598f6d9daeSMarcel Telka 		(void) memset(result, 0, sizeof (*result));
4608f6d9daeSMarcel Telka 		return (TRUE);
4617c478bd9Sstevel@tonic-gate 	}
4628f6d9daeSMarcel Telka 
4638f6d9daeSMarcel Telka 	memcpy(result, taddr, sizeof (*result));
4648f6d9daeSMarcel Telka 	free(taddr);
4658f6d9daeSMarcel Telka 
4668f6d9daeSMarcel Telka 	return (TRUE);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate  * Convert taddr to uaddr. Should be used only by
4717c478bd9Sstevel@tonic-gate  * local servers/clients. (kernel level stuff only)
4727c478bd9Sstevel@tonic-gate  */
4738f6d9daeSMarcel Telka bool_t
rpcbproc_taddr2uaddr_com(struct netbuf * taddr,char ** result,struct svc_req * rqstp)4748f6d9daeSMarcel Telka rpcbproc_taddr2uaddr_com(struct netbuf *taddr, char **result,
4758f6d9daeSMarcel Telka     struct svc_req *rqstp)
4767c478bd9Sstevel@tonic-gate {
4777c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
4787c478bd9Sstevel@tonic-gate 
4798f6d9daeSMarcel Telka 	if ((nconf = rpcbind_get_conf(rqstp->rq_xprt->xp_netid)) == NULL)
4808f6d9daeSMarcel Telka 		*result = NULL;
4818f6d9daeSMarcel Telka 	else
4828f6d9daeSMarcel Telka 		*result = taddr2uaddr(nconf, taddr);
4837c478bd9Sstevel@tonic-gate 
4848f6d9daeSMarcel Telka 	return (TRUE);
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate  * Stuff for the rmtcall service
4897c478bd9Sstevel@tonic-gate  */
4908f6d9daeSMarcel Telka bool_t
xdr_rpcb_rmtcallargs(XDR * xdrs,rpcb_rmtcallargs * objp)4918f6d9daeSMarcel Telka xdr_rpcb_rmtcallargs(XDR *xdrs, rpcb_rmtcallargs *objp)
4927c478bd9Sstevel@tonic-gate {
4938f6d9daeSMarcel Telka 	if (!xdr_u_long(xdrs, &objp->prog))
4948f6d9daeSMarcel Telka 		return (FALSE);
4958f6d9daeSMarcel Telka 	if (!xdr_u_long(xdrs, &objp->vers))
4968f6d9daeSMarcel Telka 		return (FALSE);
4978f6d9daeSMarcel Telka 	if (!xdr_u_long(xdrs, &objp->proc))
4988f6d9daeSMarcel Telka 		return (FALSE);
4998f6d9daeSMarcel Telka 	if (!xdr_bytes(xdrs, (char **)&objp->args.args_val,
5008f6d9daeSMarcel Telka 	    (uint_t *)&objp->args.args_len, ~0))
5018f6d9daeSMarcel Telka 		return (FALSE);
5028f6d9daeSMarcel Telka 	return (TRUE);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate #ifdef PORTMAP
5068f6d9daeSMarcel Telka bool_t
xdr_rmtcallres(XDR * xdrs,rmtcallres * objp)5078f6d9daeSMarcel Telka xdr_rmtcallres(XDR *xdrs, rmtcallres *objp)
5088f6d9daeSMarcel Telka {
5098f6d9daeSMarcel Telka 	if (!xdr_u_long(xdrs, &objp->port))
5107c478bd9Sstevel@tonic-gate 		return (FALSE);
5118f6d9daeSMarcel Telka 	if (!xdr_bytes(xdrs, (char **)&objp->res.res_val,
5128f6d9daeSMarcel Telka 	    (uint_t *)&objp->res.res_len, ~0))
5138f6d9daeSMarcel Telka 		return (FALSE);
5148f6d9daeSMarcel Telka 	return (TRUE);
5157c478bd9Sstevel@tonic-gate }
5168f6d9daeSMarcel Telka #endif
5177c478bd9Sstevel@tonic-gate 
5188f6d9daeSMarcel Telka bool_t
xdr_rpcb_rmtcallres(XDR * xdrs,rpcb_rmtcallres * objp)5198f6d9daeSMarcel Telka xdr_rpcb_rmtcallres(XDR *xdrs, rpcb_rmtcallres *objp)
5207c478bd9Sstevel@tonic-gate {
5218f6d9daeSMarcel Telka 	if (!xdr_string(xdrs, &objp->addr, ~0))
5228f6d9daeSMarcel Telka 		return (FALSE);
5238f6d9daeSMarcel Telka 	if (!xdr_bytes(xdrs, (char **)&objp->results.results_val,
5248f6d9daeSMarcel Telka 	    (uint_t *)&objp->results.results_len, ~0))
5258f6d9daeSMarcel Telka 		return (FALSE);
5268f6d9daeSMarcel Telka 	return (TRUE);
5277c478bd9Sstevel@tonic-gate }
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate struct rmtcallfd_list {
5307c478bd9Sstevel@tonic-gate 	int fd;
5317c478bd9Sstevel@tonic-gate 	char *netid;
5327c478bd9Sstevel@tonic-gate 	struct rmtcallfd_list *next;
5337c478bd9Sstevel@tonic-gate };
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate static struct rmtcallfd_list *rmthead;
5367c478bd9Sstevel@tonic-gate static struct rmtcallfd_list *rmttail;
5377c478bd9Sstevel@tonic-gate 
5388f6d9daeSMarcel Telka #define	MASKVAL	(POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)
5398f6d9daeSMarcel Telka 
5407c478bd9Sstevel@tonic-gate int
create_rmtcall_fd(struct netconfig * nconf)5418f6d9daeSMarcel Telka create_rmtcall_fd(struct netconfig *nconf)
5427c478bd9Sstevel@tonic-gate {
5437c478bd9Sstevel@tonic-gate 	int fd;
5447c478bd9Sstevel@tonic-gate 	struct rmtcallfd_list *rmt;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) == -1) {
5477c478bd9Sstevel@tonic-gate 		if (debugging)
5488f6d9daeSMarcel Telka 			fprintf(stderr, "create_rmtcall_fd: couldn't open "
5498f6d9daeSMarcel Telka 			    "\"%s\" (errno %d, t_errno %d)\n",
5508f6d9daeSMarcel Telka 			    nconf->nc_device, errno, t_errno);
5517c478bd9Sstevel@tonic-gate 		return (-1);
5527c478bd9Sstevel@tonic-gate 	}
5538f6d9daeSMarcel Telka 
5548f6d9daeSMarcel Telka 	if (t_bind(fd, NULL, NULL) == -1) {
5557c478bd9Sstevel@tonic-gate 		if (debugging)
5568f6d9daeSMarcel Telka 			fprintf(stderr, "create_rmtcall_fd: couldn't bind to "
5578f6d9daeSMarcel Telka 			    "fd for \"%s\" (errno %d, t_errno %d)\n",
5588f6d9daeSMarcel Telka 			    nconf->nc_device, errno, t_errno);
5597c478bd9Sstevel@tonic-gate 		return (-1);
5607c478bd9Sstevel@tonic-gate 	}
5618f6d9daeSMarcel Telka 
5628f6d9daeSMarcel Telka 	rmt = malloc(sizeof (struct rmtcallfd_list));
5637c478bd9Sstevel@tonic-gate 	if (rmt == NULL) {
5647c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
5657c478bd9Sstevel@tonic-gate 		return (-1);
5667c478bd9Sstevel@tonic-gate 	}
5678f6d9daeSMarcel Telka 
5687c478bd9Sstevel@tonic-gate 	rmt->netid = strdup(nconf->nc_netid);
5698f6d9daeSMarcel Telka 	if (rmt->netid == NULL) {
5708f6d9daeSMarcel Telka 		free(rmt);
5718f6d9daeSMarcel Telka 		syslog(LOG_ERR, "create_rmtcall_fd: no memory!");
5728f6d9daeSMarcel Telka 		return (-1);
5738f6d9daeSMarcel Telka 	}
5748f6d9daeSMarcel Telka 
5758f6d9daeSMarcel Telka 	if (svc_add_input(fd, MASKVAL, handle_reply, rmt->netid) == -1) {
5768f6d9daeSMarcel Telka 		free(rmt->netid);
5778f6d9daeSMarcel Telka 		free(rmt);
5788f6d9daeSMarcel Telka 		syslog(LOG_ERR, "create_rmtcall_fd: svc_add_input() failed!");
5798f6d9daeSMarcel Telka 		return (-1);
5808f6d9daeSMarcel Telka 	}
5818f6d9daeSMarcel Telka 
5827c478bd9Sstevel@tonic-gate 	rmt->fd = fd;
5837c478bd9Sstevel@tonic-gate 	rmt->next = NULL;
5847c478bd9Sstevel@tonic-gate 	if (rmthead == NULL) {
5857c478bd9Sstevel@tonic-gate 		rmthead = rmt;
5867c478bd9Sstevel@tonic-gate 		rmttail = rmt;
5877c478bd9Sstevel@tonic-gate 	} else {
5887c478bd9Sstevel@tonic-gate 		rmttail->next = rmt;
5897c478bd9Sstevel@tonic-gate 		rmttail = rmt;
5907c478bd9Sstevel@tonic-gate 	}
5918f6d9daeSMarcel Telka 
5927c478bd9Sstevel@tonic-gate 	return (fd);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate static int
find_rmtcallfd_by_netid(char * netid)5968f6d9daeSMarcel Telka find_rmtcallfd_by_netid(char *netid)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	struct rmtcallfd_list *rmt;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	for (rmt = rmthead; rmt != NULL; rmt = rmt->next) {
6017c478bd9Sstevel@tonic-gate 		if (strcmp(netid, rmt->netid) == 0) {
6027c478bd9Sstevel@tonic-gate 			return (rmt->fd);
6037c478bd9Sstevel@tonic-gate 		}
6047c478bd9Sstevel@tonic-gate 	}
6057c478bd9Sstevel@tonic-gate 	return (-1);
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate 
6088f6d9daeSMarcel Telka #define	MAXTIME_OFF	300	/* 5 minutes timeout for rmtcalls */
6097c478bd9Sstevel@tonic-gate 
6108f6d9daeSMarcel Telka struct finfo {
6118f6d9daeSMarcel Telka 	struct finfo	*prev;
6128f6d9daeSMarcel Telka 	struct finfo	*next;
6138f6d9daeSMarcel Telka 	int		flag;
6148f6d9daeSMarcel Telka #define	FINFO_ACTIVE	0x1
6158f6d9daeSMarcel Telka 	ulong_t		caller_xid;
6168f6d9daeSMarcel Telka 	struct netbuf	*caller_addr;
6178f6d9daeSMarcel Telka 	ulong_t		forward_xid;
6188f6d9daeSMarcel Telka 	int		forward_fd;
6198f6d9daeSMarcel Telka 	char		*uaddr;
6208f6d9daeSMarcel Telka 	struct t_unitdata *reply_data;
6218f6d9daeSMarcel Telka 	struct rpc_err	reply_error;
6228f6d9daeSMarcel Telka 	uint_t		res_len;
6238f6d9daeSMarcel Telka 	void		*res_val;
6248f6d9daeSMarcel Telka 	cond_t		cv;
6258f6d9daeSMarcel Telka };
6268f6d9daeSMarcel Telka 
6278f6d9daeSMarcel Telka /*
6288f6d9daeSMarcel Telka  * finfo_lock protects rpcb_rmtcalls, rpcb_rmtcalls_max, lastxid,
6298f6d9daeSMarcel Telka  * fihead, and fitail.
6308f6d9daeSMarcel Telka  */
6318f6d9daeSMarcel Telka static mutex_t finfo_lock = DEFAULTMUTEX;
6328f6d9daeSMarcel Telka 
6338f6d9daeSMarcel Telka static int rpcb_rmtcalls;
6348f6d9daeSMarcel Telka static int rpcb_rmtcalls_max;
6358f6d9daeSMarcel Telka static ulong_t lastxid;
6368f6d9daeSMarcel Telka static struct finfo *fihead;
6378f6d9daeSMarcel Telka static struct finfo *fitail;
6388f6d9daeSMarcel Telka 
6398f6d9daeSMarcel Telka void
set_rpcb_rmtcalls_max(int max)6408f6d9daeSMarcel Telka set_rpcb_rmtcalls_max(int max)
6418f6d9daeSMarcel Telka {
6428f6d9daeSMarcel Telka 	(void) mutex_lock(&finfo_lock);
6438f6d9daeSMarcel Telka 	rpcb_rmtcalls_max = max;
6448f6d9daeSMarcel Telka 	if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
6458f6d9daeSMarcel Telka 		assert(fitail != NULL);
6468f6d9daeSMarcel Telka 		(void) cond_signal(&fitail->cv);
6477c478bd9Sstevel@tonic-gate 	}
6488f6d9daeSMarcel Telka 	(void) mutex_unlock(&finfo_lock);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate  * Call a remote procedure service.  This procedure is very quiet when things
6537c478bd9Sstevel@tonic-gate  * go wrong.  The proc is written to support broadcast rpc.  In the broadcast
6547c478bd9Sstevel@tonic-gate  * case, a machine should shut-up instead of complain, lest the requestor be
6557c478bd9Sstevel@tonic-gate  * overrun with complaints at the expense of not hearing a valid reply.
6567c478bd9Sstevel@tonic-gate  * When receiving a request and verifying that the service exists, we
6577c478bd9Sstevel@tonic-gate  *
6587c478bd9Sstevel@tonic-gate  *	receive the request
6597c478bd9Sstevel@tonic-gate  *
6607c478bd9Sstevel@tonic-gate  *	open a new TLI endpoint on the same transport on which we received
6617c478bd9Sstevel@tonic-gate  *	the original request
6627c478bd9Sstevel@tonic-gate  *
6637c478bd9Sstevel@tonic-gate  *	remember the original request's XID (which requires knowing the format
6647c478bd9Sstevel@tonic-gate  *	of the svc_dg_data structure)
6657c478bd9Sstevel@tonic-gate  *
6667c478bd9Sstevel@tonic-gate  *	forward the request, with a new XID, to the requested service,
6677c478bd9Sstevel@tonic-gate  *	remembering the XID used to send this request (for later use in
6687c478bd9Sstevel@tonic-gate  *	reassociating the answer with the original request), the requestor's
6697c478bd9Sstevel@tonic-gate  *	address, the file descriptor on which the forwarded request is
6708f6d9daeSMarcel Telka  *	made and the service's address
6717c478bd9Sstevel@tonic-gate  *
6728f6d9daeSMarcel Telka  *	wait for either the timeout or the condition variable is signalled from
6738f6d9daeSMarcel Telka  *	handle_reply().
6747c478bd9Sstevel@tonic-gate  *
6757c478bd9Sstevel@tonic-gate  * At some time in the future, a reply will be received from the service to
6768f6d9daeSMarcel Telka  * which we forwarded the request.  At that time, svc_run() detect that the
6778f6d9daeSMarcel Telka  * socket used was for forwarding and call handle_reply() to
6787c478bd9Sstevel@tonic-gate  *
6797c478bd9Sstevel@tonic-gate  *	receive the reply
6807c478bd9Sstevel@tonic-gate  *
6817c478bd9Sstevel@tonic-gate  *	bundle the reply, along with the service's universal address
6827c478bd9Sstevel@tonic-gate  *
6838f6d9daeSMarcel Telka  *	put the reply into the particular finfo
6848f6d9daeSMarcel Telka  *
6858f6d9daeSMarcel Telka  *	signal the condition variable.
6867c478bd9Sstevel@tonic-gate  */
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate #define	RPC_BUF_MAX	65536	/* can be raised if required */
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate /*
6917c478bd9Sstevel@tonic-gate  *  This is from ../ypcmd/yp_b.h
6927c478bd9Sstevel@tonic-gate  *  It does not appear in <rpcsvc/yp_prot.h>
6937c478bd9Sstevel@tonic-gate  */
6947c478bd9Sstevel@tonic-gate #define	YPBINDPROG ((ulong_t)100007)
6957c478bd9Sstevel@tonic-gate #define	YPBINDPROC_SETDOM ((ulong_t)2)
6967c478bd9Sstevel@tonic-gate 
6978f6d9daeSMarcel Telka /*
6988f6d9daeSMarcel Telka  * reply_type - which proc number
6998f6d9daeSMarcel Telka  * versnum - which vers was called
7008f6d9daeSMarcel Telka  */
7017c478bd9Sstevel@tonic-gate void
rpcbproc_callit_com(struct svc_req * rqstp,SVCXPRT * transp,ulong_t reply_type,int versnum)7028f6d9daeSMarcel Telka rpcbproc_callit_com(struct svc_req *rqstp, SVCXPRT *transp, ulong_t reply_type,
7038f6d9daeSMarcel Telka     int versnum)
7047c478bd9Sstevel@tonic-gate {
7058f6d9daeSMarcel Telka 	struct t_info tinfo;
7068f6d9daeSMarcel Telka 	uint_t sendsz;
7078f6d9daeSMarcel Telka 
7088f6d9daeSMarcel Telka 	rpcb_rmtcallargs arg;
7098f6d9daeSMarcel Telka 	rpcblist_ptr rbl;
7108f6d9daeSMarcel Telka 
7117c478bd9Sstevel@tonic-gate 	struct netconfig *nconf;
7127c478bd9Sstevel@tonic-gate 	struct netbuf *caller;
7138f6d9daeSMarcel Telka 	struct nd_mergearg ma;
7148f6d9daeSMarcel Telka 	int stat;
7158f6d9daeSMarcel Telka 
7168f6d9daeSMarcel Telka 	int fd;
7177c478bd9Sstevel@tonic-gate 	struct svc_dg_data *bd;
7188f6d9daeSMarcel Telka 	struct finfo *fi;
7198f6d9daeSMarcel Telka 
7208f6d9daeSMarcel Telka 	struct rpc_msg call_msg;
7218f6d9daeSMarcel Telka 	char outbuf[RPC_BUF_MAX];
7228f6d9daeSMarcel Telka 	char *outbuf_alloc = NULL;
7237c478bd9Sstevel@tonic-gate 	XDR outxdr;
7248f6d9daeSMarcel Telka 	bool_t outxdr_created = FALSE;
7258f6d9daeSMarcel Telka 
7267c478bd9Sstevel@tonic-gate 	AUTH *auth;
7278f6d9daeSMarcel Telka 
7288f6d9daeSMarcel Telka 	struct t_unitdata tu_data;
7298f6d9daeSMarcel Telka 	struct netbuf *na;
7308f6d9daeSMarcel Telka 
7318f6d9daeSMarcel Telka 	timestruc_t to;
7328f6d9daeSMarcel Telka 
7338f6d9daeSMarcel Telka 	(void) mutex_lock(&finfo_lock);
7348f6d9daeSMarcel Telka 	if (!allow_indirect || rpcb_rmtcalls_max == 0) {
7358f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
7368f6d9daeSMarcel Telka 		return;
7378f6d9daeSMarcel Telka 	}
7388f6d9daeSMarcel Telka 	(void) mutex_unlock(&finfo_lock);
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	if (t_getinfo(transp->xp_fd, &tinfo) == -1) {
7417c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
7427c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
7437c478bd9Sstevel@tonic-gate 		return;
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 	if (tinfo.servtype != T_CLTS)
7467c478bd9Sstevel@tonic-gate 		return;	/* Only datagram type accepted */
7478f6d9daeSMarcel Telka 
7487c478bd9Sstevel@tonic-gate 	sendsz = __rpc_get_t_size(0, tinfo.tsdu);
7497c478bd9Sstevel@tonic-gate 	if (sendsz == 0) {	/* data transfer not supported */
7507c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
7517c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
7527c478bd9Sstevel@tonic-gate 		return;
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 	/*
7557c478bd9Sstevel@tonic-gate 	 * Should be multiple of 4 for XDR.
7567c478bd9Sstevel@tonic-gate 	 */
7577c478bd9Sstevel@tonic-gate 	sendsz = ((sendsz + 3) / 4) * 4;
7587c478bd9Sstevel@tonic-gate 
7598f6d9daeSMarcel Telka 	(void) memset((char *)&arg, 0, sizeof (arg));
7608f6d9daeSMarcel Telka 	if (!svc_getargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg)) {
7617c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
7627c478bd9Sstevel@tonic-gate 			svcerr_decode(transp);
7637c478bd9Sstevel@tonic-gate 		if (debugging)
7647c478bd9Sstevel@tonic-gate 			fprintf(stderr,
7657c478bd9Sstevel@tonic-gate 			"rpcbproc_callit_com:  svc_getargs failed\n");
7667c478bd9Sstevel@tonic-gate 		goto error;
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	/*
7707c478bd9Sstevel@tonic-gate 	 * Disallow calling rpcbind for certain procedures.
7717c478bd9Sstevel@tonic-gate 	 * Allow calling NULLPROC - per man page on rpcb_rmtcall().
7727c478bd9Sstevel@tonic-gate 	 * switch is in alphabetical order.
7737c478bd9Sstevel@tonic-gate 	 */
7748f6d9daeSMarcel Telka 	if (arg.proc != NULLPROC) {
7758f6d9daeSMarcel Telka 		switch (arg.prog) {
7767c478bd9Sstevel@tonic-gate 		case KEY_PROG:
7777c478bd9Sstevel@tonic-gate 			if (debugging)
7787c478bd9Sstevel@tonic-gate 				fprintf(stderr,
7798f6d9daeSMarcel Telka 				    "rpcbind: rejecting KEY_PROG(%d)\n",
7808f6d9daeSMarcel Telka 				    arg.proc);
7817c478bd9Sstevel@tonic-gate 			goto error;
7827c478bd9Sstevel@tonic-gate 		case MOUNTPROG:
7838f6d9daeSMarcel Telka 			if (arg.proc != MOUNTPROC_MNT)
7847c478bd9Sstevel@tonic-gate 				break;
7857c478bd9Sstevel@tonic-gate 			/*
7867c478bd9Sstevel@tonic-gate 			 * In Solaris 2.6, the host-based accesss control
7877c478bd9Sstevel@tonic-gate 			 * is done by the NFS server on each request.
7887c478bd9Sstevel@tonic-gate 			 * Prior to 2.6 we rely on mountd.
7897c478bd9Sstevel@tonic-gate 			 */
7907c478bd9Sstevel@tonic-gate 			if (debugging)
7917c478bd9Sstevel@tonic-gate 				fprintf(stderr,
7928f6d9daeSMarcel Telka 				    "rpcbind: rejecting MOUNTPROG(%d)\n",
7938f6d9daeSMarcel Telka 				    arg.proc);
7947c478bd9Sstevel@tonic-gate 			goto error;
7957c478bd9Sstevel@tonic-gate 		case NFS_ACL_PROGRAM:
7967c478bd9Sstevel@tonic-gate 			if (debugging)
7977c478bd9Sstevel@tonic-gate 				fprintf(stderr,
7988f6d9daeSMarcel Telka 				    "rpcbind: rejecting NFS_ACL_PROGRAM(%d)\n",
7998f6d9daeSMarcel Telka 				    arg.proc);
8007c478bd9Sstevel@tonic-gate 			goto error;
8017c478bd9Sstevel@tonic-gate 		case NFS_PROGRAM:
8027c478bd9Sstevel@tonic-gate 			/* also NFS3_PROGRAM */
8037c478bd9Sstevel@tonic-gate 			if (debugging)
8047c478bd9Sstevel@tonic-gate 				fprintf(stderr,
8058f6d9daeSMarcel Telka 				    "rpcbind: rejecting NFS_PROGRAM(%d)\n",
8068f6d9daeSMarcel Telka 				    arg.proc);
8077c478bd9Sstevel@tonic-gate 			goto error;
8087c478bd9Sstevel@tonic-gate 		case RPCBPROG:
8097c478bd9Sstevel@tonic-gate 			/*
8107c478bd9Sstevel@tonic-gate 			 * Disallow calling rpcbind for certain procedures.
8117c478bd9Sstevel@tonic-gate 			 * Luckily Portmap set/unset/callit also have same
8127c478bd9Sstevel@tonic-gate 			 * procedure numbers.  So, will not check for those.
8137c478bd9Sstevel@tonic-gate 			 */
8148f6d9daeSMarcel Telka 			switch (arg.proc) {
8157c478bd9Sstevel@tonic-gate 			case RPCBPROC_SET:
8167c478bd9Sstevel@tonic-gate 			case RPCBPROC_UNSET:
8177c478bd9Sstevel@tonic-gate 			case RPCBPROC_CALLIT:
8187c478bd9Sstevel@tonic-gate 			case RPCBPROC_INDIRECT:
8197c478bd9Sstevel@tonic-gate 				if (reply_type == RPCBPROC_INDIRECT)
8207c478bd9Sstevel@tonic-gate 					svcerr_weakauth(transp); /* XXX */
8217c478bd9Sstevel@tonic-gate 				if (debugging)
8228f6d9daeSMarcel Telka 					fprintf(stderr, "rpcbproc_callit_com: "
8238f6d9daeSMarcel Telka 					    "calling RPCBPROG procs SET, "
8248f6d9daeSMarcel Telka 					    "UNSET, CALLIT, or INDIRECT not "
8258f6d9daeSMarcel Telka 					    "allowed\n");
8267c478bd9Sstevel@tonic-gate 				goto error;
8277c478bd9Sstevel@tonic-gate 			default:
8287c478bd9Sstevel@tonic-gate 				/*
8297c478bd9Sstevel@tonic-gate 				 * Ideally, we should have called rpcb_service()
8307c478bd9Sstevel@tonic-gate 				 * or pmap_service() with appropriate parameters
8317c478bd9Sstevel@tonic-gate 				 * instead of going about in a roundabout
8327c478bd9Sstevel@tonic-gate 				 * manner.  Hopefully, this case should happen
8337c478bd9Sstevel@tonic-gate 				 * rarely.
8347c478bd9Sstevel@tonic-gate 				 */
8357c478bd9Sstevel@tonic-gate 				break;
8367c478bd9Sstevel@tonic-gate 			}
8377c478bd9Sstevel@tonic-gate 			break;
8387c478bd9Sstevel@tonic-gate 		case RQUOTAPROG:
8397c478bd9Sstevel@tonic-gate 			if (debugging)
8407c478bd9Sstevel@tonic-gate 				fprintf(stderr,
8418f6d9daeSMarcel Telka 				    "rpcbind: rejecting RQUOTAPROG(%d)\n",
8428f6d9daeSMarcel Telka 				    arg.proc);
8437c478bd9Sstevel@tonic-gate 			goto error;
8447c478bd9Sstevel@tonic-gate 		case YPPASSWDPROG:
8457c478bd9Sstevel@tonic-gate 			if (debugging)
8467c478bd9Sstevel@tonic-gate 				fprintf(stderr,
8478f6d9daeSMarcel Telka 				    "rpcbind: rejecting YPPASSWDPROG(%d)\n",
8488f6d9daeSMarcel Telka 				    arg.proc);
8497c478bd9Sstevel@tonic-gate 			goto error;
8507c478bd9Sstevel@tonic-gate 		case YPU_PROG:
8517c478bd9Sstevel@tonic-gate 			if (debugging)
8527c478bd9Sstevel@tonic-gate 				fprintf(stderr,
8538f6d9daeSMarcel Telka 				    "rpcbind: rejecting YPU_PROG(%d)\n",
8548f6d9daeSMarcel Telka 				    arg.proc);
8557c478bd9Sstevel@tonic-gate 			goto error;
8567c478bd9Sstevel@tonic-gate 		case YPBINDPROG:
8578f6d9daeSMarcel Telka 			if (arg.proc != YPBINDPROC_SETDOM)
8587c478bd9Sstevel@tonic-gate 				break;
8597c478bd9Sstevel@tonic-gate 			if (debugging)
8607c478bd9Sstevel@tonic-gate 				fprintf(stderr,
8618f6d9daeSMarcel Telka 				    "rpcbind: rejecting YPBINDPROG(%d)\n",
8628f6d9daeSMarcel Telka 				    arg.proc);
8637c478bd9Sstevel@tonic-gate 			goto error;
8647c478bd9Sstevel@tonic-gate 		case YPPROG:
8658f6d9daeSMarcel Telka 			switch (arg.proc) {
8667c478bd9Sstevel@tonic-gate 			case YPPROC_FIRST:
8677c478bd9Sstevel@tonic-gate 			case YPPROC_NEXT:
8687c478bd9Sstevel@tonic-gate 			case YPPROC_MATCH:
8697c478bd9Sstevel@tonic-gate 			case YPPROC_ALL:
8707c478bd9Sstevel@tonic-gate 				if (debugging)
8717c478bd9Sstevel@tonic-gate 					fprintf(stderr,
8728f6d9daeSMarcel Telka 					    "rpcbind: rejecting YPPROG(%d)\n",
8738f6d9daeSMarcel Telka 					    arg.proc);
8747c478bd9Sstevel@tonic-gate 				goto error;
8757c478bd9Sstevel@tonic-gate 			default:
8767c478bd9Sstevel@tonic-gate 				break;
8777c478bd9Sstevel@tonic-gate 			}
8787c478bd9Sstevel@tonic-gate 			break;
8797c478bd9Sstevel@tonic-gate 		default:
8807c478bd9Sstevel@tonic-gate 			break;
8817c478bd9Sstevel@tonic-gate 		}
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate 
8848f6d9daeSMarcel Telka 	(void) rw_rdlock(&list_rbl_lock);
8858f6d9daeSMarcel Telka 	rbl = find_service(arg.prog, arg.vers, transp->xp_netid);
8867c478bd9Sstevel@tonic-gate 
8878f6d9daeSMarcel Telka 	rpcbs_rmtcall(versnum - PMAPVERS, reply_type, arg.prog, arg.vers,
8888f6d9daeSMarcel Telka 	    arg.proc, transp->xp_netid, rbl);
8897c478bd9Sstevel@tonic-gate 
8908f6d9daeSMarcel Telka 	if (rbl == NULL) {
8918f6d9daeSMarcel Telka 		(void) rw_unlock(&list_rbl_lock);
8927c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
8937c478bd9Sstevel@tonic-gate 			svcerr_noprog(transp);
8947c478bd9Sstevel@tonic-gate 		goto error;
8957c478bd9Sstevel@tonic-gate 	}
8968f6d9daeSMarcel Telka 	if (rbl->rpcb_map.r_vers != arg.vers) {
8977c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT) {
8987c478bd9Sstevel@tonic-gate 			ulong_t vers_low, vers_high;
8997c478bd9Sstevel@tonic-gate 
9008f6d9daeSMarcel Telka 			find_versions(arg.prog, transp->xp_netid,
9018f6d9daeSMarcel Telka 			    &vers_low, &vers_high);
9028f6d9daeSMarcel Telka 			(void) rw_unlock(&list_rbl_lock);
9037c478bd9Sstevel@tonic-gate 			svcerr_progvers(transp, vers_low, vers_high);
9048f6d9daeSMarcel Telka 		} else {
9058f6d9daeSMarcel Telka 			(void) rw_unlock(&list_rbl_lock);
9067c478bd9Sstevel@tonic-gate 		}
9077c478bd9Sstevel@tonic-gate 		goto error;
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	/*
9118f6d9daeSMarcel Telka 	 * Check whether this entry is valid and a server is present
9128f6d9daeSMarcel Telka 	 * Mergeaddr() returns NULL if no such entry is present, and
9138f6d9daeSMarcel Telka 	 * returns "" if the entry was present but the server is not
9148f6d9daeSMarcel Telka 	 * present (i.e., it crashed).
9157c478bd9Sstevel@tonic-gate 	 */
9167c478bd9Sstevel@tonic-gate 	if (reply_type == RPCBPROC_INDIRECT) {
9178f6d9daeSMarcel Telka 		char *uaddr = mergeaddr(transp, transp->xp_netid,
9188f6d9daeSMarcel Telka 		    rbl->rpcb_map.r_addr, NULL);
9197c478bd9Sstevel@tonic-gate 		if ((uaddr == (char *)NULL) || uaddr[0] == '\0') {
9208f6d9daeSMarcel Telka 			(void) rw_unlock(&list_rbl_lock);
9217c478bd9Sstevel@tonic-gate 			svcerr_noprog(transp);
9227c478bd9Sstevel@tonic-gate 			goto error;
9237c478bd9Sstevel@tonic-gate 		} else {
9248f6d9daeSMarcel Telka 			free(uaddr);
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 	}
9278f6d9daeSMarcel Telka 
9287c478bd9Sstevel@tonic-gate 	nconf = rpcbind_get_conf(transp->xp_netid);
9298f6d9daeSMarcel Telka 	if (nconf == NULL) {
9308f6d9daeSMarcel Telka 		(void) rw_unlock(&list_rbl_lock);
9317c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
9327c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
9337c478bd9Sstevel@tonic-gate 		if (debugging)
9347c478bd9Sstevel@tonic-gate 			fprintf(stderr,
9358f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  rpcbind_get_conf failed\n");
9367c478bd9Sstevel@tonic-gate 		goto error;
9377c478bd9Sstevel@tonic-gate 	}
9388f6d9daeSMarcel Telka 
9398f6d9daeSMarcel Telka 	caller = svc_getrpccaller(transp);
9407c478bd9Sstevel@tonic-gate 	ma.c_uaddr = taddr2uaddr(nconf, caller);
9417c478bd9Sstevel@tonic-gate 	ma.s_uaddr = rbl->rpcb_map.r_addr;
9428f6d9daeSMarcel Telka 
9437c478bd9Sstevel@tonic-gate 	/*
9448f6d9daeSMarcel Telka 	 * A mergeaddr operation allocates a string, which it stores in
9458f6d9daeSMarcel Telka 	 * ma.m_uaddr.  It's passed to forward_register() and is
9468f6d9daeSMarcel Telka 	 * eventually freed by forward_destroy().
9477c478bd9Sstevel@tonic-gate 	 */
9487c478bd9Sstevel@tonic-gate 	stat = netdir_options(nconf, ND_MERGEADDR, 0, (char *)&ma);
9498f6d9daeSMarcel Telka 	(void) rw_unlock(&list_rbl_lock);
9508f6d9daeSMarcel Telka 	free(ma.c_uaddr);
9517c478bd9Sstevel@tonic-gate 	if (stat)
9527c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "netdir_merge failed for %s: %s",
9538f6d9daeSMarcel Telka 		    nconf->nc_netid, netdir_sperror());
9548f6d9daeSMarcel Telka 
9557c478bd9Sstevel@tonic-gate 	if ((fd = find_rmtcallfd_by_netid(nconf->nc_netid)) == -1) {
9567c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
9577c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
9588f6d9daeSMarcel Telka 		free(ma.m_uaddr);
9597c478bd9Sstevel@tonic-gate 		goto error;
9607c478bd9Sstevel@tonic-gate 	}
9618f6d9daeSMarcel Telka 
962f48205beScasper 	bd = get_svc_dg_data(transp);
9638f6d9daeSMarcel Telka 
9648f6d9daeSMarcel Telka 	assert(!MUTEX_HELD(&finfo_lock));
9658f6d9daeSMarcel Telka 	fi = forward_register(bd->su_xid, caller, fd, ma.m_uaddr);
9668f6d9daeSMarcel Telka 	if (fi == NULL) {
9678f6d9daeSMarcel Telka 		/*  forward_register failed.  Perhaps no memory. */
9688f6d9daeSMarcel Telka 		free(ma.m_uaddr);
9698f6d9daeSMarcel Telka 		if (debugging)
9708f6d9daeSMarcel Telka 			fprintf(stderr,
9718f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  forward_register failed\n");
9728f6d9daeSMarcel Telka 		assert(!MUTEX_HELD(&finfo_lock));
9738f6d9daeSMarcel Telka 		goto error;
9748f6d9daeSMarcel Telka 	}
9758f6d9daeSMarcel Telka 	/* forward_register() returns with finfo_lock held when successful */
9768f6d9daeSMarcel Telka 	assert(MUTEX_HELD(&finfo_lock));
9778f6d9daeSMarcel Telka 
9788f6d9daeSMarcel Telka 	if (fi->flag & FINFO_ACTIVE) {
9797c478bd9Sstevel@tonic-gate 		/*
9807c478bd9Sstevel@tonic-gate 		 * A duplicate request for the slow server.  Let's not
9817c478bd9Sstevel@tonic-gate 		 * beat on it any more.
9827c478bd9Sstevel@tonic-gate 		 */
9838f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
9848f6d9daeSMarcel Telka 		free(ma.m_uaddr);
9857c478bd9Sstevel@tonic-gate 		if (debugging)
9867c478bd9Sstevel@tonic-gate 			fprintf(stderr,
9878f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  duplicate request\n");
9887c478bd9Sstevel@tonic-gate 		goto error;
9897c478bd9Sstevel@tonic-gate 	}
9908f6d9daeSMarcel Telka 	fi->flag |= FINFO_ACTIVE;
9917c478bd9Sstevel@tonic-gate 
9928f6d9daeSMarcel Telka 	call_msg.rm_xid = fi->forward_xid;
9937c478bd9Sstevel@tonic-gate 	call_msg.rm_direction = CALL;
9947c478bd9Sstevel@tonic-gate 	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
9958f6d9daeSMarcel Telka 	call_msg.rm_call.cb_prog = arg.prog;
9968f6d9daeSMarcel Telka 	call_msg.rm_call.cb_vers = arg.vers;
9978f6d9daeSMarcel Telka 
9987c478bd9Sstevel@tonic-gate 	if (sendsz > RPC_BUF_MAX) {
9997c478bd9Sstevel@tonic-gate 		outbuf_alloc = malloc(sendsz);
10007c478bd9Sstevel@tonic-gate 		if (outbuf_alloc == NULL) {
10018f6d9daeSMarcel Telka 			forward_destroy(fi);
10028f6d9daeSMarcel Telka 			(void) mutex_unlock(&finfo_lock);
10037c478bd9Sstevel@tonic-gate 			if (reply_type == RPCBPROC_INDIRECT)
10047c478bd9Sstevel@tonic-gate 				svcerr_systemerr(transp);
10057c478bd9Sstevel@tonic-gate 			if (debugging)
10067c478bd9Sstevel@tonic-gate 				fprintf(stderr,
10078f6d9daeSMarcel Telka 				    "rpcbproc_callit_com:  No memory!\n");
10087c478bd9Sstevel@tonic-gate 			goto error;
10097c478bd9Sstevel@tonic-gate 		}
10107c478bd9Sstevel@tonic-gate 		xdrmem_create(&outxdr, outbuf_alloc, sendsz, XDR_ENCODE);
10117c478bd9Sstevel@tonic-gate 	} else {
10127c478bd9Sstevel@tonic-gate 		xdrmem_create(&outxdr, outbuf, sendsz, XDR_ENCODE);
10137c478bd9Sstevel@tonic-gate 	}
10148f6d9daeSMarcel Telka 	outxdr_created = TRUE;
10158f6d9daeSMarcel Telka 
10167c478bd9Sstevel@tonic-gate 	if (!xdr_callhdr(&outxdr, &call_msg)) {
10178f6d9daeSMarcel Telka 		forward_destroy(fi);
10188f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
10197c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
10207c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
10217c478bd9Sstevel@tonic-gate 		if (debugging)
10227c478bd9Sstevel@tonic-gate 			fprintf(stderr,
10238f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  xdr_callhdr failed\n");
10247c478bd9Sstevel@tonic-gate 		goto error;
10257c478bd9Sstevel@tonic-gate 	}
10268f6d9daeSMarcel Telka 
10278f6d9daeSMarcel Telka 	if (!xdr_u_long(&outxdr, &arg.proc)) {
10288f6d9daeSMarcel Telka 		forward_destroy(fi);
10298f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
10307c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
10317c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
10327c478bd9Sstevel@tonic-gate 		if (debugging)
10337c478bd9Sstevel@tonic-gate 			fprintf(stderr,
10348f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  xdr_u_long failed\n");
10357c478bd9Sstevel@tonic-gate 		goto error;
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	if (rqstp->rq_cred.oa_flavor == AUTH_NULL) {
10397c478bd9Sstevel@tonic-gate 		auth = authnone_create();
10407c478bd9Sstevel@tonic-gate 	} else if (rqstp->rq_cred.oa_flavor == AUTH_SYS) {
10417c478bd9Sstevel@tonic-gate 		struct authsys_parms *au;
10427c478bd9Sstevel@tonic-gate 
1043*b1cdc720SAlex Wilson 		CTASSERT(sizeof (struct authsys_parms) <= RQCRED_SIZE);
10447c478bd9Sstevel@tonic-gate 		au = (struct authsys_parms *)rqstp->rq_clntcred;
10458f6d9daeSMarcel Telka 		auth = authsys_create(au->aup_machname, au->aup_uid,
10468f6d9daeSMarcel Telka 		    au->aup_gid, au->aup_len, au->aup_gids);
10477c478bd9Sstevel@tonic-gate 		if (auth == NULL) /* fall back */
10487c478bd9Sstevel@tonic-gate 			auth = authnone_create();
10497c478bd9Sstevel@tonic-gate 	} else {
10507c478bd9Sstevel@tonic-gate 		/* we do not support any other authentication scheme */
10518f6d9daeSMarcel Telka 		forward_destroy(fi);
10528f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
10537c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
10547c478bd9Sstevel@tonic-gate 			svcerr_weakauth(transp); /* XXX too strong.. */
10558f6d9daeSMarcel Telka 		if (debugging)
10568f6d9daeSMarcel Telka 			fprintf(stderr, "rpcbproc_callit_com:  oa_flavor != "
10578f6d9daeSMarcel Telka 			    "AUTH_NONE and oa_flavor != AUTH_SYS\n");
10587c478bd9Sstevel@tonic-gate 		goto error;
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 	if (auth == NULL) {
10618f6d9daeSMarcel Telka 		forward_destroy(fi);
10628f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
10637c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
10647c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
10657c478bd9Sstevel@tonic-gate 		if (debugging)
10668f6d9daeSMarcel Telka 			fprintf(stderr, "rpcbproc_callit_com:  "
10678f6d9daeSMarcel Telka 			    "authwhatever_create returned NULL\n");
10687c478bd9Sstevel@tonic-gate 		goto error;
10697c478bd9Sstevel@tonic-gate 	}
10707c478bd9Sstevel@tonic-gate 	if (!AUTH_MARSHALL(auth, &outxdr)) {
10718f6d9daeSMarcel Telka 		forward_destroy(fi);
10728f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
10737c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
10747c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
10757c478bd9Sstevel@tonic-gate 		AUTH_DESTROY(auth);
10767c478bd9Sstevel@tonic-gate 		if (debugging)
10777c478bd9Sstevel@tonic-gate 			fprintf(stderr,
10788f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  AUTH_MARSHALL failed\n");
10797c478bd9Sstevel@tonic-gate 		goto error;
10807c478bd9Sstevel@tonic-gate 	}
10817c478bd9Sstevel@tonic-gate 	AUTH_DESTROY(auth);
10828f6d9daeSMarcel Telka 
10838f6d9daeSMarcel Telka 	if (!xdr_opaque(&outxdr, arg.args.args_val, arg.args.args_len)) {
10848f6d9daeSMarcel Telka 		forward_destroy(fi);
10858f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
10867c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
10877c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
10887c478bd9Sstevel@tonic-gate 		if (debugging)
10897c478bd9Sstevel@tonic-gate 			fprintf(stderr,
10908f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  xdr_opaque failed\n");
10917c478bd9Sstevel@tonic-gate 		goto error;
10927c478bd9Sstevel@tonic-gate 	}
10938f6d9daeSMarcel Telka 
10948f6d9daeSMarcel Telka 	tu_data.udata.len = XDR_GETPOS(&outxdr);
10957c478bd9Sstevel@tonic-gate 	if (outbuf_alloc)
10967c478bd9Sstevel@tonic-gate 		tu_data.udata.buf = outbuf_alloc;
10977c478bd9Sstevel@tonic-gate 	else
10987c478bd9Sstevel@tonic-gate 		tu_data.udata.buf = outbuf;
10997c478bd9Sstevel@tonic-gate 	tu_data.opt.len = 0;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	na = uaddr2taddr(nconf, ma.m_uaddr);
11027c478bd9Sstevel@tonic-gate 	if (!na) {
11038f6d9daeSMarcel Telka 		forward_destroy(fi);
11048f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
11057c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
11067c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
11077c478bd9Sstevel@tonic-gate 		goto error;
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 	tu_data.addr = *na;
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	if (t_sndudata(fd, &tu_data) == -1) {
11128f6d9daeSMarcel Telka 		int err = errno;
11138f6d9daeSMarcel Telka 		forward_destroy(fi);
11148f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
11158f6d9daeSMarcel Telka 
11168f6d9daeSMarcel Telka 		netdir_free((char *)na, ND_ADDR);
11178f6d9daeSMarcel Telka 
11188f6d9daeSMarcel Telka 		if (reply_type == RPCBPROC_INDIRECT)
11198f6d9daeSMarcel Telka 			svcerr_systemerr(transp);
11207c478bd9Sstevel@tonic-gate 		if (debugging)
11217c478bd9Sstevel@tonic-gate 			fprintf(stderr,
11228f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  t_sndudata failed:  "
11238f6d9daeSMarcel Telka 			    "t_errno %d, errno %d\n", t_errno, err);
11248f6d9daeSMarcel Telka 		goto error;
11258f6d9daeSMarcel Telka 	}
11268f6d9daeSMarcel Telka 
11278f6d9daeSMarcel Telka 	netdir_free((char *)na, ND_ADDR);
11288f6d9daeSMarcel Telka 	xdr_destroy(&outxdr);
11298f6d9daeSMarcel Telka 	outxdr_created = FALSE;
11308f6d9daeSMarcel Telka 	if (outbuf_alloc != NULL) {
11318f6d9daeSMarcel Telka 		free(outbuf_alloc);
11328f6d9daeSMarcel Telka 		outbuf_alloc = NULL;
11338f6d9daeSMarcel Telka 	}
11348f6d9daeSMarcel Telka 	svc_freeargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg);
11358f6d9daeSMarcel Telka 
11368f6d9daeSMarcel Telka 	to.tv_sec = time(NULL) + MAXTIME_OFF;
11378f6d9daeSMarcel Telka 	to.tv_nsec = 0;
11388f6d9daeSMarcel Telka 
11398f6d9daeSMarcel Telka 	while (fi->reply_data == NULL &&
11408f6d9daeSMarcel Telka 	    cond_timedwait(&fi->cv, &finfo_lock, &to) != ETIME)
11418f6d9daeSMarcel Telka 		;
11428f6d9daeSMarcel Telka 
11438f6d9daeSMarcel Telka 	if (fi->reply_data == NULL) {
11448f6d9daeSMarcel Telka 		forward_destroy(fi);
11458f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
11468f6d9daeSMarcel Telka 
11477c478bd9Sstevel@tonic-gate 		if (reply_type == RPCBPROC_INDIRECT)
11487c478bd9Sstevel@tonic-gate 			svcerr_systemerr(transp);
11498f6d9daeSMarcel Telka 		if (debugging)
11508f6d9daeSMarcel Telka 			(void) fprintf(stderr,
11518f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  timeout\n");
11528f6d9daeSMarcel Telka 		return;
11538f6d9daeSMarcel Telka 	}
11548f6d9daeSMarcel Telka 
11558f6d9daeSMarcel Telka 	if (fi->reply_error.re_status != RPC_SUCCESS) {
11568f6d9daeSMarcel Telka 		forward_destroy(fi);
11578f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
11588f6d9daeSMarcel Telka 
11598f6d9daeSMarcel Telka 		if (reply_type == RPCBPROC_INDIRECT)
11608f6d9daeSMarcel Telka 			svcerr_systemerr(transp);
11618f6d9daeSMarcel Telka 		if (debugging)
11628f6d9daeSMarcel Telka 			(void) fprintf(stderr,
11638f6d9daeSMarcel Telka 			    "rpcbproc_callit_com:  error in reply:  %s\n",
11648f6d9daeSMarcel Telka 			    clnt_sperrno(fi->reply_error.re_status));
11658f6d9daeSMarcel Telka 		return;
11667c478bd9Sstevel@tonic-gate 	}
11678f6d9daeSMarcel Telka 
11688f6d9daeSMarcel Telka 	switch (versnum) {
11698f6d9daeSMarcel Telka #ifdef PORTMAP
11708f6d9daeSMarcel Telka 	case PMAPVERS:
11718f6d9daeSMarcel Telka 		{
11728f6d9daeSMarcel Telka 			rmtcallres result;
11738f6d9daeSMarcel Telka 			int h1, h2, h3, h4, p1, p2;
11748f6d9daeSMarcel Telka 
11758f6d9daeSMarcel Telka 			/* interpret the universal address for TCP/IP */
11768f6d9daeSMarcel Telka 			if (sscanf(fi->uaddr, "%d.%d.%d.%d.%d.%d",
11778f6d9daeSMarcel Telka 			    &h1, &h2, &h3, &h4, &p1, &p2) != 6)
11788f6d9daeSMarcel Telka 				break;
11798f6d9daeSMarcel Telka 
11808f6d9daeSMarcel Telka 			result.port = ((p1 & 0xff) << 8) + (p2 & 0xff);
11818f6d9daeSMarcel Telka 			result.res.res_len = fi->res_len;
11828f6d9daeSMarcel Telka 			result.res.res_val = fi->res_val;
11838f6d9daeSMarcel Telka 
11848f6d9daeSMarcel Telka 			svc_sendreply(transp, xdr_rmtcallres, (char *)&result);
11858f6d9daeSMarcel Telka 		}
11868f6d9daeSMarcel Telka 		break;
11878f6d9daeSMarcel Telka #endif
11888f6d9daeSMarcel Telka 	case RPCBVERS:
11898f6d9daeSMarcel Telka 	case RPCBVERS4:
11908f6d9daeSMarcel Telka 		{
11918f6d9daeSMarcel Telka 			rpcb_rmtcallres result;
11928f6d9daeSMarcel Telka 
11938f6d9daeSMarcel Telka 			result.addr = fi->uaddr;
11948f6d9daeSMarcel Telka 			result.results.results_len = fi->res_len;
11958f6d9daeSMarcel Telka 			result.results.results_val = fi->res_val;
11968f6d9daeSMarcel Telka 
11978f6d9daeSMarcel Telka 			svc_sendreply(transp, xdr_rpcb_rmtcallres,
11988f6d9daeSMarcel Telka 			    (char *)&result);
11998f6d9daeSMarcel Telka 		}
12008f6d9daeSMarcel Telka 		break;
12018f6d9daeSMarcel Telka 	}
12028f6d9daeSMarcel Telka 
12038f6d9daeSMarcel Telka 	forward_destroy(fi);
12048f6d9daeSMarcel Telka 	(void) mutex_unlock(&finfo_lock);
12058f6d9daeSMarcel Telka 
12068f6d9daeSMarcel Telka 	return;
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate error:
12098f6d9daeSMarcel Telka 	if (outxdr_created)
12108f6d9daeSMarcel Telka 		xdr_destroy(&outxdr);
12118f6d9daeSMarcel Telka 	free(outbuf_alloc);
12128f6d9daeSMarcel Telka 	svc_freeargs(transp, xdr_rpcb_rmtcallargs, (char *)&arg);
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate 
12158f6d9daeSMarcel Telka static struct finfo *forward_find(ulong_t, char *);
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate /*
12188f6d9daeSMarcel Telka  * Adds an entry into the finfo list for the given request. Returns the finfo
12198f6d9daeSMarcel Telka  * and finfo_lock is left held.  If duplicate request, returns finfo with
12208f6d9daeSMarcel Telka  * FINFO_ACTIVE, else returns finfo without FINFO_ACTIVE.
12218f6d9daeSMarcel Telka  * If failed, returns NULL and finfo_lock is left unheld.
12227c478bd9Sstevel@tonic-gate  */
12238f6d9daeSMarcel Telka static struct finfo *
forward_register(ulong_t caller_xid,struct netbuf * caller_addr,int forward_fd,char * uaddr)12248f6d9daeSMarcel Telka forward_register(ulong_t caller_xid, struct netbuf *caller_addr, int forward_fd,
12258f6d9daeSMarcel Telka     char *uaddr)
12267c478bd9Sstevel@tonic-gate {
12278f6d9daeSMarcel Telka 	struct finfo	*fi;
12288f6d9daeSMarcel Telka 
12298f6d9daeSMarcel Telka 	(void) mutex_lock(&finfo_lock);
12308f6d9daeSMarcel Telka 	if (rpcb_rmtcalls_max == 0) {
12318f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
12328f6d9daeSMarcel Telka 		return (NULL);
12338f6d9daeSMarcel Telka 	}
12348f6d9daeSMarcel Telka 
12353582b7c1Sgt 	/*
12363582b7c1Sgt 	 * initialization: once this has happened, lastxid will
12378f6d9daeSMarcel Telka 	 * never be 0 again, when entering or returning from this function.
12383582b7c1Sgt 	 */
12398f6d9daeSMarcel Telka 	if (lastxid == 0)
12408f6d9daeSMarcel Telka 		lastxid = time(NULL);
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	/*
12438f6d9daeSMarcel Telka 	 * Check if it is an duplicate entry
12447c478bd9Sstevel@tonic-gate 	 */
12458f6d9daeSMarcel Telka 	for (fi = fihead; fi != NULL; fi = fi->next) {
12468f6d9daeSMarcel Telka 		if (fi->caller_xid == caller_xid &&
12478f6d9daeSMarcel Telka 		    netbufcmp(fi->caller_addr, caller_addr)) {
12488f6d9daeSMarcel Telka 			assert(fi->flag & FINFO_ACTIVE);
12498f6d9daeSMarcel Telka 			return (fi);
12507c478bd9Sstevel@tonic-gate 		}
12517c478bd9Sstevel@tonic-gate 	}
12528f6d9daeSMarcel Telka 
12538f6d9daeSMarcel Telka 	fi = malloc(sizeof (*fi));
12548f6d9daeSMarcel Telka 	if (fi == NULL) {
12558f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
12568f6d9daeSMarcel Telka 		return (NULL);
12578f6d9daeSMarcel Telka 	}
12588f6d9daeSMarcel Telka 
12598f6d9daeSMarcel Telka 	if ((fi->caller_addr = netbufdup(caller_addr)) == NULL) {
12608f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
12618f6d9daeSMarcel Telka 		free(fi);
12628f6d9daeSMarcel Telka 		return (NULL);
12638f6d9daeSMarcel Telka 	}
12648f6d9daeSMarcel Telka 
12658f6d9daeSMarcel Telka 	/*
12668f6d9daeSMarcel Telka 	 * Generate new xid and make sure it is unique.
12678f6d9daeSMarcel Telka 	 */
12688f6d9daeSMarcel Telka 	do {
12698f6d9daeSMarcel Telka 		lastxid++;
12708f6d9daeSMarcel Telka 		/* avoid lastxid wraparound to 0 */
12718f6d9daeSMarcel Telka 		if (lastxid == 0)
12728f6d9daeSMarcel Telka 			lastxid = 1;
12738f6d9daeSMarcel Telka 	} while (forward_find(lastxid, uaddr) != NULL);
12748f6d9daeSMarcel Telka 
12758f6d9daeSMarcel Telka 	fi->prev = NULL;
12768f6d9daeSMarcel Telka 	fi->next = fihead;
1277e9b15d23SMarcel Telka 	if (fihead != NULL)
1278e9b15d23SMarcel Telka 		fihead->prev = fi;
12798f6d9daeSMarcel Telka 	fihead = fi;
12808f6d9daeSMarcel Telka 	if (fitail == NULL)
12818f6d9daeSMarcel Telka 		fitail = fi;
12828f6d9daeSMarcel Telka 
12838f6d9daeSMarcel Telka 	fi->flag = 0;
12848f6d9daeSMarcel Telka 	fi->caller_xid = caller_xid;
12858f6d9daeSMarcel Telka 
12868f6d9daeSMarcel Telka 	fi->forward_xid = lastxid;
12878f6d9daeSMarcel Telka 	fi->forward_fd = forward_fd;
12888f6d9daeSMarcel Telka 
12897c478bd9Sstevel@tonic-gate 	/*
12907c478bd9Sstevel@tonic-gate 	 * Though uaddr is not allocated here, it will still be freed
12918f6d9daeSMarcel Telka 	 * from forward_destroy().
12927c478bd9Sstevel@tonic-gate 	 */
12938f6d9daeSMarcel Telka 	fi->uaddr = uaddr;
12947c478bd9Sstevel@tonic-gate 
12958f6d9daeSMarcel Telka 	fi->reply_data = NULL;
12968f6d9daeSMarcel Telka 	(void) cond_init(&fi->cv, USYNC_THREAD, NULL);
12977c478bd9Sstevel@tonic-gate 
12988f6d9daeSMarcel Telka 	rpcb_rmtcalls++;
12998f6d9daeSMarcel Telka 	if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
13008f6d9daeSMarcel Telka 		assert(fitail != fi);
13018f6d9daeSMarcel Telka 		(void) cond_signal(&fitail->cv);
13027c478bd9Sstevel@tonic-gate 	}
13038f6d9daeSMarcel Telka 
13048f6d9daeSMarcel Telka 	return (fi);
13057c478bd9Sstevel@tonic-gate }
13067c478bd9Sstevel@tonic-gate 
13078f6d9daeSMarcel Telka static void
forward_destroy(struct finfo * fi)13088f6d9daeSMarcel Telka forward_destroy(struct finfo *fi)
13097c478bd9Sstevel@tonic-gate {
13108f6d9daeSMarcel Telka 	assert(MUTEX_HELD(&finfo_lock));
13118f6d9daeSMarcel Telka 	assert(fi->flag & FINFO_ACTIVE);
13127c478bd9Sstevel@tonic-gate 
13138f6d9daeSMarcel Telka 	if (fihead == fi) {
13148f6d9daeSMarcel Telka 		assert(fi->prev == NULL);
13158f6d9daeSMarcel Telka 		fihead = fi->next;
13168f6d9daeSMarcel Telka 	} else {
13178f6d9daeSMarcel Telka 		fi->prev->next = fi->next;
13188f6d9daeSMarcel Telka 	}
13198f6d9daeSMarcel Telka 
13208f6d9daeSMarcel Telka 	if (fitail == fi) {
13218f6d9daeSMarcel Telka 		assert(fi->next == NULL);
13228f6d9daeSMarcel Telka 		fitail = fi->prev;
13238f6d9daeSMarcel Telka 	} else {
13248f6d9daeSMarcel Telka 		fi->next->prev = fi->prev;
13258f6d9daeSMarcel Telka 	}
13268f6d9daeSMarcel Telka 
13278f6d9daeSMarcel Telka 	netbuffree(fi->caller_addr);
13288f6d9daeSMarcel Telka 	free(fi->uaddr);
13298f6d9daeSMarcel Telka 	if (fi->reply_data != NULL)
13308f6d9daeSMarcel Telka 		t_free((char *)fi->reply_data, T_UNITDATA);
13318f6d9daeSMarcel Telka 	(void) cond_destroy(&fi->cv);
13328f6d9daeSMarcel Telka 
13338f6d9daeSMarcel Telka 	free(fi);
13348f6d9daeSMarcel Telka 
13358f6d9daeSMarcel Telka 	rpcb_rmtcalls--;
13368f6d9daeSMarcel Telka 	if (rpcb_rmtcalls > rpcb_rmtcalls_max) {
13378f6d9daeSMarcel Telka 		assert(fitail != NULL);
13388f6d9daeSMarcel Telka 		(void) cond_signal(&fitail->cv);
13397c478bd9Sstevel@tonic-gate 	}
13407c478bd9Sstevel@tonic-gate }
13417c478bd9Sstevel@tonic-gate 
13428f6d9daeSMarcel Telka static struct finfo *
forward_find(ulong_t reply_xid,char * uaddr)13438f6d9daeSMarcel Telka forward_find(ulong_t reply_xid, char *uaddr)
13447c478bd9Sstevel@tonic-gate {
13458f6d9daeSMarcel Telka 	struct finfo *fi;
13467c478bd9Sstevel@tonic-gate 
13478f6d9daeSMarcel Telka 	assert(MUTEX_HELD(&finfo_lock));
13488f6d9daeSMarcel Telka 
13498f6d9daeSMarcel Telka 	for (fi = fihead; fi != NULL; fi = fi->next) {
13508f6d9daeSMarcel Telka 		if (fi->forward_xid == reply_xid &&
13518f6d9daeSMarcel Telka 		    strcmp(fi->uaddr, uaddr) == 0)
13528f6d9daeSMarcel Telka 			return (fi);
13537c478bd9Sstevel@tonic-gate 	}
13548f6d9daeSMarcel Telka 
13558f6d9daeSMarcel Telka 	return (NULL);
13567c478bd9Sstevel@tonic-gate }
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate static int
netbufcmp(struct netbuf * n1,struct netbuf * n2)13598f6d9daeSMarcel Telka netbufcmp(struct netbuf *n1, struct netbuf *n2)
13607c478bd9Sstevel@tonic-gate {
13617c478bd9Sstevel@tonic-gate 	return ((n1->len != n2->len) || memcmp(n1->buf, n2->buf, n1->len));
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate static struct netbuf *
netbufdup(struct netbuf * ap)13658f6d9daeSMarcel Telka netbufdup(struct netbuf *ap)
13667c478bd9Sstevel@tonic-gate {
13678f6d9daeSMarcel Telka 	struct netbuf *np;
13687c478bd9Sstevel@tonic-gate 
13698f6d9daeSMarcel Telka 	np = malloc(sizeof (struct netbuf) + ap->len);
13707c478bd9Sstevel@tonic-gate 	if (np) {
13717c478bd9Sstevel@tonic-gate 		np->maxlen = np->len = ap->len;
13727c478bd9Sstevel@tonic-gate 		np->buf = ((char *)np) + sizeof (struct netbuf);
13737c478bd9Sstevel@tonic-gate 		(void) memcpy(np->buf, ap->buf, ap->len);
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate 	return (np);
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate static void
netbuffree(struct netbuf * ap)13798f6d9daeSMarcel Telka netbuffree(struct netbuf *ap)
13807c478bd9Sstevel@tonic-gate {
13818f6d9daeSMarcel Telka 	free(ap);
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate static void
handle_reply(svc_input_id_t id,int fd,unsigned int events,void * cookie)13858f6d9daeSMarcel Telka handle_reply(svc_input_id_t id, int fd, unsigned int events, void *cookie)
13867c478bd9Sstevel@tonic-gate {
13878f6d9daeSMarcel Telka 	struct t_unitdata *tr_data;
13888f6d9daeSMarcel Telka 	int res;
13897c478bd9Sstevel@tonic-gate 
13908f6d9daeSMarcel Telka 	unsigned int inlen;
13918f6d9daeSMarcel Telka 	char *buffer;
13928f6d9daeSMarcel Telka 	XDR reply_xdrs;
13937c478bd9Sstevel@tonic-gate 
13948f6d9daeSMarcel Telka 	struct rpc_msg reply_msg;
13958f6d9daeSMarcel Telka 	unsigned int pos;
13968f6d9daeSMarcel Telka 	unsigned int len;
13977c478bd9Sstevel@tonic-gate 
13988f6d9daeSMarcel Telka 	struct netconfig *nconf;
13997c478bd9Sstevel@tonic-gate 	char *uaddr = NULL;
14007c478bd9Sstevel@tonic-gate 
14018f6d9daeSMarcel Telka 	struct finfo *fi;
14027c478bd9Sstevel@tonic-gate 
14038f6d9daeSMarcel Telka 	tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA,
14048f6d9daeSMarcel Telka 	    T_ADDR | T_UDATA);
14058f6d9daeSMarcel Telka 	if (tr_data == NULL) {
14068f6d9daeSMarcel Telka 		syslog(LOG_ERR, "handle_reply: t_alloc failed!");
14077c478bd9Sstevel@tonic-gate 		return;
14087c478bd9Sstevel@tonic-gate 	}
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	do {
14118f6d9daeSMarcel Telka 		int moreflag = 0;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 		if (errno == EINTR)
14147c478bd9Sstevel@tonic-gate 			errno = 0;
14157c478bd9Sstevel@tonic-gate 		res = t_rcvudata(fd, tr_data, &moreflag);
14167c478bd9Sstevel@tonic-gate 		if (moreflag & T_MORE) {
14177c478bd9Sstevel@tonic-gate 			/* Drop this packet - we have no more space. */
14187c478bd9Sstevel@tonic-gate 			if (debugging)
14198f6d9daeSMarcel Telka 				fprintf(stderr, "handle_reply:  recvd packet "
14208f6d9daeSMarcel Telka 				    "with T_MORE flag set\n");
14217c478bd9Sstevel@tonic-gate 			goto done;
14227c478bd9Sstevel@tonic-gate 		}
14238f6d9daeSMarcel Telka 	} while (res < 0 && t_errno == TSYSERR && errno == EINTR);
14247c478bd9Sstevel@tonic-gate 
14258f6d9daeSMarcel Telka 	if (res < 0) {
14267c478bd9Sstevel@tonic-gate 		if (debugging)
14278f6d9daeSMarcel Telka 			fprintf(stderr, "handle_reply:  t_rcvudata returned "
14288f6d9daeSMarcel Telka 			    "%d, t_errno %d, errno %d\n", res, t_errno, errno);
14298f6d9daeSMarcel Telka 
14308f6d9daeSMarcel Telka 		if (t_errno == TLOOK)
14318f6d9daeSMarcel Telka 			(void) t_rcvuderr(fd, NULL);
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 		goto done;
14347c478bd9Sstevel@tonic-gate 	}
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	inlen = tr_data->udata.len;
14377c478bd9Sstevel@tonic-gate 	buffer = tr_data->udata.buf;
14388f6d9daeSMarcel Telka 	assert(buffer != NULL);
14398f6d9daeSMarcel Telka 	xdrmem_create(&reply_xdrs, buffer, inlen, XDR_DECODE);
14408f6d9daeSMarcel Telka 
14417c478bd9Sstevel@tonic-gate 	reply_msg.acpted_rply.ar_verf = _null_auth;
14427c478bd9Sstevel@tonic-gate 	reply_msg.acpted_rply.ar_results.where = 0;
14437c478bd9Sstevel@tonic-gate 	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	if (!xdr_replymsg(&reply_xdrs, &reply_msg)) {
14468f6d9daeSMarcel Telka 		xdr_destroy(&reply_xdrs);
14477c478bd9Sstevel@tonic-gate 		if (debugging)
14487c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
14498f6d9daeSMarcel Telka 			    "handle_reply:  xdr_replymsg failed\n");
14507c478bd9Sstevel@tonic-gate 		goto done;
14517c478bd9Sstevel@tonic-gate 	}
14528f6d9daeSMarcel Telka 	pos = XDR_GETPOS(&reply_xdrs);
14538f6d9daeSMarcel Telka 	xdr_destroy(&reply_xdrs);
14548f6d9daeSMarcel Telka 
14558f6d9daeSMarcel Telka 	len = inlen - pos;
14568f6d9daeSMarcel Telka 
14578f6d9daeSMarcel Telka 	nconf = rpcbind_get_conf((char *)cookie);
14588f6d9daeSMarcel Telka 	if (nconf == NULL) {
14598f6d9daeSMarcel Telka 		syslog(LOG_ERR, "handle_reply: rpcbind_get_conf failed!");
14607c478bd9Sstevel@tonic-gate 		goto done;
14617c478bd9Sstevel@tonic-gate 	}
14628f6d9daeSMarcel Telka 	uaddr = taddr2uaddr(nconf, &tr_data->addr);
14638f6d9daeSMarcel Telka 	if (uaddr == NULL) {
14648f6d9daeSMarcel Telka 		syslog(LOG_ERR, "handle_reply: taddr2uaddr failed!");
14657c478bd9Sstevel@tonic-gate 		goto done;
14667c478bd9Sstevel@tonic-gate 	}
14678f6d9daeSMarcel Telka 
14688f6d9daeSMarcel Telka 	(void) mutex_lock(&finfo_lock);
14698f6d9daeSMarcel Telka 	fi = forward_find(reply_msg.rm_xid, uaddr);
14708f6d9daeSMarcel Telka 	if (fi == NULL) {
14718f6d9daeSMarcel Telka 		(void) mutex_unlock(&finfo_lock);
14728f6d9daeSMarcel Telka 		goto done;
14737c478bd9Sstevel@tonic-gate 	}
14748f6d9daeSMarcel Telka 
14758f6d9daeSMarcel Telka 	fi->reply_data = tr_data;
14768f6d9daeSMarcel Telka 	tr_data = NULL;
14778f6d9daeSMarcel Telka 
14788f6d9daeSMarcel Telka 	__seterr_reply(&reply_msg, &fi->reply_error);
14798f6d9daeSMarcel Telka 
14808f6d9daeSMarcel Telka 	fi->res_len = len;
14818f6d9daeSMarcel Telka 	fi->res_val = &buffer[pos];
14828f6d9daeSMarcel Telka 
14838f6d9daeSMarcel Telka 	(void) cond_signal(&fi->cv);
14848f6d9daeSMarcel Telka 	(void) mutex_unlock(&finfo_lock);
14858f6d9daeSMarcel Telka 
14867c478bd9Sstevel@tonic-gate done:
14878f6d9daeSMarcel Telka 	free(uaddr);
14887c478bd9Sstevel@tonic-gate 	if (tr_data)
14897c478bd9Sstevel@tonic-gate 		t_free((char *)tr_data, T_UNITDATA);
14907c478bd9Sstevel@tonic-gate }
14917c478bd9Sstevel@tonic-gate 
14928f6d9daeSMarcel Telka /*
14938f6d9daeSMarcel Telka  * prog: Program Number
14948f6d9daeSMarcel Telka  * netid: Transport Provider token
14958f6d9daeSMarcel Telka  * lowvp: Low version number
14968f6d9daeSMarcel Telka  * highvp: High version number
14978f6d9daeSMarcel Telka  */
14987c478bd9Sstevel@tonic-gate static void
find_versions(rpcprog_t prog,char * netid,rpcvers_t * lowvp,rpcvers_t * highvp)14998f6d9daeSMarcel Telka find_versions(rpcprog_t prog, char *netid, rpcvers_t *lowvp, rpcvers_t *highvp)
15007c478bd9Sstevel@tonic-gate {
15018f6d9daeSMarcel Telka 	rpcblist_ptr rbl;
15028f6d9daeSMarcel Telka 	rpcvers_t lowv = 0;
15038f6d9daeSMarcel Telka 	rpcvers_t highv = 0;
15048f6d9daeSMarcel Telka 
15058f6d9daeSMarcel Telka 	assert(RW_LOCK_HELD(&list_rbl_lock));
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
15087c478bd9Sstevel@tonic-gate 		if ((rbl->rpcb_map.r_prog != prog) ||
15098f6d9daeSMarcel Telka 		    (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))
15107c478bd9Sstevel@tonic-gate 			continue;
15117c478bd9Sstevel@tonic-gate 		if (lowv == 0) {
15127c478bd9Sstevel@tonic-gate 			highv = rbl->rpcb_map.r_vers;
15137c478bd9Sstevel@tonic-gate 			lowv = highv;
15147c478bd9Sstevel@tonic-gate 		} else if (rbl->rpcb_map.r_vers < lowv) {
15157c478bd9Sstevel@tonic-gate 			lowv = rbl->rpcb_map.r_vers;
15167c478bd9Sstevel@tonic-gate 		} else if (rbl->rpcb_map.r_vers > highv) {
15177c478bd9Sstevel@tonic-gate 			highv = rbl->rpcb_map.r_vers;
15187c478bd9Sstevel@tonic-gate 		}
15197c478bd9Sstevel@tonic-gate 	}
15208f6d9daeSMarcel Telka 
15217c478bd9Sstevel@tonic-gate 	*lowvp = lowv;
15227c478bd9Sstevel@tonic-gate 	*highvp = highv;
15237c478bd9Sstevel@tonic-gate }
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate /*
15267c478bd9Sstevel@tonic-gate  * returns the item with the given program, version number and netid.
15277c478bd9Sstevel@tonic-gate  * If that version number is not found, it returns the item with that
15287c478bd9Sstevel@tonic-gate  * program number, so that address is now returned to the caller. The
15297c478bd9Sstevel@tonic-gate  * caller when makes a call to this program, version number, the call
15307c478bd9Sstevel@tonic-gate  * will fail and it will return with PROGVERS_MISMATCH. The user can
15317c478bd9Sstevel@tonic-gate  * then determine the highest and the lowest version number for this
15327c478bd9Sstevel@tonic-gate  * program using clnt_geterr() and use those program version numbers.
15337c478bd9Sstevel@tonic-gate  *
15347c478bd9Sstevel@tonic-gate  * Returns the RPCBLIST for the given prog, vers and netid
15358f6d9daeSMarcel Telka  *
15368f6d9daeSMarcel Telka  * prog: Program Number
15378f6d9daeSMarcel Telka  * vers: Version Number
15388f6d9daeSMarcel Telka  * netid: Transport Provider token
15397c478bd9Sstevel@tonic-gate  */
15407c478bd9Sstevel@tonic-gate static rpcblist_ptr
find_service(rpcprog_t prog,rpcvers_t vers,char * netid)15418f6d9daeSMarcel Telka find_service(rpcprog_t prog, rpcvers_t vers, char *netid)
15427c478bd9Sstevel@tonic-gate {
15438f6d9daeSMarcel Telka 	rpcblist_ptr hit = NULL;
15448f6d9daeSMarcel Telka 	rpcblist_ptr rbl;
15458f6d9daeSMarcel Telka 
15468f6d9daeSMarcel Telka 	assert(RW_LOCK_HELD(&list_rbl_lock));
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
15497c478bd9Sstevel@tonic-gate 		if ((rbl->rpcb_map.r_prog != prog) ||
15508f6d9daeSMarcel Telka 		    (strcasecmp(rbl->rpcb_map.r_netid, netid) != 0))
15517c478bd9Sstevel@tonic-gate 			continue;
15527c478bd9Sstevel@tonic-gate 		hit = rbl;
15537c478bd9Sstevel@tonic-gate 		if (rbl->rpcb_map.r_vers == vers)
15547c478bd9Sstevel@tonic-gate 			break;
15557c478bd9Sstevel@tonic-gate 	}
15568f6d9daeSMarcel Telka 
15577c478bd9Sstevel@tonic-gate 	return (hit);
15587c478bd9Sstevel@tonic-gate }
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate /*
15617c478bd9Sstevel@tonic-gate  * If the caller is from our zone and we know
15627c478bd9Sstevel@tonic-gate  * who it is, we return the uid.
15637c478bd9Sstevel@tonic-gate  */
15647c478bd9Sstevel@tonic-gate uid_t
rpcb_caller_uid(SVCXPRT * transp)15657c478bd9Sstevel@tonic-gate rpcb_caller_uid(SVCXPRT *transp)
15667c478bd9Sstevel@tonic-gate {
15677c478bd9Sstevel@tonic-gate 	ucred_t *uc = alloca(ucred_size());
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	if (svc_getcallerucred(transp, &uc) != 0 ||
15707c478bd9Sstevel@tonic-gate 	    (ucred_getzoneid(uc)) != myzone) {
15717c478bd9Sstevel@tonic-gate 		return (-1);
15727c478bd9Sstevel@tonic-gate 	} else {
15737c478bd9Sstevel@tonic-gate 		return (ucred_geteuid(uc));
15747c478bd9Sstevel@tonic-gate 	}
15757c478bd9Sstevel@tonic-gate }
15767c478bd9Sstevel@tonic-gate 
15777c478bd9Sstevel@tonic-gate /*
15787c478bd9Sstevel@tonic-gate  * Copies the name associated with the uid of the caller and returns
15797c478bd9Sstevel@tonic-gate  * a pointer to it.  Similar to getwd().
15807c478bd9Sstevel@tonic-gate  */
15817c478bd9Sstevel@tonic-gate char *
getowner(SVCXPRT * transp,char * owner)15828f6d9daeSMarcel Telka getowner(SVCXPRT *transp, char *owner)
15837c478bd9Sstevel@tonic-gate {
15847c478bd9Sstevel@tonic-gate 	uid_t uid = rpcb_caller_uid(transp);
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	switch (uid) {
15877c478bd9Sstevel@tonic-gate 	case -1:
15887c478bd9Sstevel@tonic-gate 		return (strcpy(owner, "unknown"));
15897c478bd9Sstevel@tonic-gate 	case 0:
15907c478bd9Sstevel@tonic-gate 		return (strcpy(owner, "superuser"));
15917c478bd9Sstevel@tonic-gate 	default:
15927c478bd9Sstevel@tonic-gate 		(void) sprintf(owner, "%u", uid);
15937c478bd9Sstevel@tonic-gate 		return (owner);
15947c478bd9Sstevel@tonic-gate 	}
15957c478bd9Sstevel@tonic-gate }
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate #ifdef PORTMAP
15987c478bd9Sstevel@tonic-gate /*
15997c478bd9Sstevel@tonic-gate  * Add this to the pmap list only if it is UDP or TCP.
16007c478bd9Sstevel@tonic-gate  */
16017c478bd9Sstevel@tonic-gate static int
add_pmaplist(RPCB * arg)16028f6d9daeSMarcel Telka add_pmaplist(RPCB *arg)
16037c478bd9Sstevel@tonic-gate {
16047c478bd9Sstevel@tonic-gate 	pmap pmap;
16057c478bd9Sstevel@tonic-gate 	pmaplist *pml;
16067c478bd9Sstevel@tonic-gate 	int h1, h2, h3, h4, p1, p2;
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	if (strcmp(arg->r_netid, udptrans) == 0) {
16097c478bd9Sstevel@tonic-gate 		/* It is UDP! */
16107c478bd9Sstevel@tonic-gate 		pmap.pm_prot = IPPROTO_UDP;
16117c478bd9Sstevel@tonic-gate 	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
16127c478bd9Sstevel@tonic-gate 		/* It is TCP */
16137c478bd9Sstevel@tonic-gate 		pmap.pm_prot = IPPROTO_TCP;
16147c478bd9Sstevel@tonic-gate 	} else
16157c478bd9Sstevel@tonic-gate 		/* Not a IP protocol */
16167c478bd9Sstevel@tonic-gate 		return (0);
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	/* interpret the universal address for TCP/IP */
16197c478bd9Sstevel@tonic-gate 	if (sscanf(arg->r_addr, "%d.%d.%d.%d.%d.%d",
16208f6d9daeSMarcel Telka 	    &h1, &h2, &h3, &h4, &p1, &p2) != 6)
16217c478bd9Sstevel@tonic-gate 		return (0);
16227c478bd9Sstevel@tonic-gate 	pmap.pm_port = ((p1 & 0xff) << 8) + (p2 & 0xff);
16237c478bd9Sstevel@tonic-gate 	pmap.pm_prog = arg->r_prog;
16247c478bd9Sstevel@tonic-gate 	pmap.pm_vers = arg->r_vers;
16257c478bd9Sstevel@tonic-gate 	/*
16267c478bd9Sstevel@tonic-gate 	 * add to END of list
16277c478bd9Sstevel@tonic-gate 	 */
16287c478bd9Sstevel@tonic-gate 	pml = (pmaplist *) malloc((uint_t)sizeof (pmaplist));
16297c478bd9Sstevel@tonic-gate 	if (pml == NULL) {
16307c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_ERR, "rpcbind: no memory!\n");
16317c478bd9Sstevel@tonic-gate 		return (1);
16327c478bd9Sstevel@tonic-gate 	}
16337c478bd9Sstevel@tonic-gate 	pml->pml_map = pmap;
16347c478bd9Sstevel@tonic-gate 	pml->pml_next = NULL;
16358f6d9daeSMarcel Telka 
16368f6d9daeSMarcel Telka 	(void) rw_wrlock(&list_pml_lock);
16377c478bd9Sstevel@tonic-gate 	if (list_pml == NULL) {
16387c478bd9Sstevel@tonic-gate 		list_pml = pml;
16397c478bd9Sstevel@tonic-gate 	} else {
16407c478bd9Sstevel@tonic-gate 		pmaplist *fnd;
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 		/* Attach to the end of the list */
16437c478bd9Sstevel@tonic-gate 		for (fnd = list_pml; fnd->pml_next; fnd = fnd->pml_next)
16447c478bd9Sstevel@tonic-gate 			;
16457c478bd9Sstevel@tonic-gate 		fnd->pml_next = pml;
16467c478bd9Sstevel@tonic-gate 	}
16478f6d9daeSMarcel Telka 	(void) rw_unlock(&list_pml_lock);
16488f6d9daeSMarcel Telka 
16497c478bd9Sstevel@tonic-gate 	return (0);
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate /*
16537c478bd9Sstevel@tonic-gate  * Delete this from the pmap list only if it is UDP or TCP.
16547c478bd9Sstevel@tonic-gate  */
16553582b7c1Sgt int
del_pmaplist(RPCB * arg)16563582b7c1Sgt del_pmaplist(RPCB *arg)
16577c478bd9Sstevel@tonic-gate {
16588f6d9daeSMarcel Telka 	pmaplist *pml;
16597c478bd9Sstevel@tonic-gate 	pmaplist *prevpml, *fnd;
16608f6d9daeSMarcel Telka 	rpcport_t prot;
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 	if (strcmp(arg->r_netid, udptrans) == 0) {
16637c478bd9Sstevel@tonic-gate 		/* It is UDP! */
16647c478bd9Sstevel@tonic-gate 		prot = IPPROTO_UDP;
16657c478bd9Sstevel@tonic-gate 	} else if (strcmp(arg->r_netid, tcptrans) == 0) {
16667c478bd9Sstevel@tonic-gate 		/* It is TCP */
16677c478bd9Sstevel@tonic-gate 		prot = IPPROTO_TCP;
16688f6d9daeSMarcel Telka 	} else if (arg->r_netid[0] == '\0') {
16697c478bd9Sstevel@tonic-gate 		prot = 0;	/* Remove all occurrences */
16707c478bd9Sstevel@tonic-gate 	} else {
16717c478bd9Sstevel@tonic-gate 		/* Not a IP protocol */
16727c478bd9Sstevel@tonic-gate 		return (0);
16737c478bd9Sstevel@tonic-gate 	}
16748f6d9daeSMarcel Telka 
16758f6d9daeSMarcel Telka 	assert(RW_WRITE_HELD(&list_pml_lock));
16768f6d9daeSMarcel Telka 
16777c478bd9Sstevel@tonic-gate 	for (prevpml = NULL, pml = list_pml; pml; /* cstyle */) {
16787c478bd9Sstevel@tonic-gate 		if ((pml->pml_map.pm_prog != arg->r_prog) ||
167936e852a1SRaja Andra 		    (pml->pml_map.pm_vers != arg->r_vers) ||
168036e852a1SRaja Andra 		    (prot && (pml->pml_map.pm_prot != prot))) {
16817c478bd9Sstevel@tonic-gate 			/* both pml & prevpml move forwards */
16827c478bd9Sstevel@tonic-gate 			prevpml = pml;
16837c478bd9Sstevel@tonic-gate 			pml = pml->pml_next;
16847c478bd9Sstevel@tonic-gate 			continue;
16857c478bd9Sstevel@tonic-gate 		}
16867c478bd9Sstevel@tonic-gate 		/* found it; pml moves forward, prevpml stays */
16877c478bd9Sstevel@tonic-gate 		fnd = pml;
16887c478bd9Sstevel@tonic-gate 		pml = pml->pml_next;
16897c478bd9Sstevel@tonic-gate 		if (prevpml == NULL)
16907c478bd9Sstevel@tonic-gate 			list_pml = pml;
16917c478bd9Sstevel@tonic-gate 		else
16927c478bd9Sstevel@tonic-gate 			prevpml->pml_next = pml;
16938f6d9daeSMarcel Telka 		free(fnd);
16947c478bd9Sstevel@tonic-gate 	}
16958f6d9daeSMarcel Telka 
16967c478bd9Sstevel@tonic-gate 	return (0);
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate #endif /* PORTMAP */
1699