Esempio n. 1
0
/*
 * rpcb_log - log request for service
 */
void
rpcb_log(boolean_t verdict, SVCXPRT *transp, rpcproc_t proc, rpcprog_t prog,
         boolean_t pm)
{
    struct netconfig *conf;
    const char *client = "unknown";
    char *uaddr;
    char buf[BUFSIZ];

    /*
     * Transform the transport address into something printable.
     */
    if ((conf = rpcbind_get_conf(transp->xp_netid)) == 0) {
        syslog(LOG_WARNING,
               "unknown transport (rpcbind_get_conf failed)");
    } else if (strcmp(conf->nc_protofmly, "inet") == 0 ||
               strcmp(conf->nc_protofmly, "inet6") == 0) {
        client = sgen_toa(svc_getgencaller(transp));
    } else if ((uaddr = taddr2uaddr(conf, &(transp->xp_rtaddr))) == NULL) {
        syslog(LOG_WARNING, "unknown address (taddr2uaddr failed)");
    } else {
        (void) snprintf(buf, sizeof (buf), "%s(%s)",
                        conf->nc_protofmly, uaddr);
        free(uaddr);
        client = buf;
    }
    qsyslog(verdict ? allow_severity : deny_severity,
            "%sconnect from %s to %s(%s)", verdict ? "" : "refused ",
            client, find_procname(proc, pm), find_progname(prog));
}
Esempio n. 2
0
void
rpcbs_rmtcall(rpcvers_t rtype, rpcproc_t rpcbproc, rpcprog_t prog,
	      rpcvers_t vers, rpcproc_t proc, char *netid, rpcblist_ptr rbl)
{
	rpcbs_rmtcalllist *rl;
	struct netconfig *nconf;

	if (rtype > RPCBVERS_STAT)
		return;
	for (rl = inf[rtype].rmtinfo; rl; rl = rl->next) {

		if(rl->netid == NULL)
			return;

		if ((rl->prog == prog) && (rl->vers == vers) &&
		    (rl->proc == proc) &&
		    (strcmp(rl->netid, netid) == 0)) {
			if ((rbl == NULL) ||
			    (rbl->rpcb_map.r_vers != vers))
				rl->failure++;
			else
				rl->success++;
			if (rpcbproc == RPCBPROC_INDIRECT)
				rl->indirect++;
			return;
		}
	}
	nconf = rpcbind_get_conf(netid);
	if (nconf == NULL) {
		return;
	}
	rl = (rpcbs_rmtcalllist *) malloc(sizeof (rpcbs_rmtcalllist));
	if (rl == NULL) {
		return;
	}
	rl->prog = prog;
	rl->vers = vers;
	rl->proc = proc;
	rl->netid = nconf->nc_netid;
	if ((rbl == NULL) ||
		    (rbl->rpcb_map.r_vers != vers)) {
		rl->failure = 1;
		rl->success = 0;
	} else {
		rl->failure = 0;
		rl->success = 1;
	}
	rl->indirect = 1;
	rl->next = inf[rtype].rmtinfo;
	inf[rtype].rmtinfo = rl;
	return;
}
Esempio n. 3
0
void
rpcbs_getaddr(rpcvers_t rtype, rpcprog_t prog, rpcvers_t vers, char *netid,
	      char *uaddr)
{
	rpcbs_addrlist *al;
	struct netconfig *nconf;

	if (rtype >= RPCBVERS_STAT)
		return;
	for (al = inf[rtype].addrinfo; al; al = al->next) {

		if(al->netid == NULL)
			return;
		if ((al->prog == prog) && (al->vers == vers) &&
		    (strcmp(al->netid, netid) == 0)) {
			if ((uaddr == NULL) || (uaddr[0] == 0))
				al->failure++;
			else
				al->success++;
			return;
		}
	}
	nconf = rpcbind_get_conf(netid);
	if (nconf == NULL) {
		return;
	}
	al = (rpcbs_addrlist *) malloc(sizeof (rpcbs_addrlist));
	if (al == NULL) {
		return;
	}
	al->prog = prog;
	al->vers = vers;
	al->netid = nconf->nc_netid;
	if ((uaddr == NULL) || (uaddr[0] == 0)) {
		al->failure = 1;
		al->success = 0;
	} else {
		al->failure = 0;
		al->success = 1;
	}
	al->next = inf[rtype].addrinfo;
	inf[rtype].addrinfo = al;
}
Esempio n. 4
0
/* ARGSUSED */
static void *
rpcbproc_getaddr_4_local(void *arg, struct svc_req *rqstp, SVCXPRT *transp,
			 rpcvers_t rpcbversnum /*__unused*/)
{
	RPCB *regp = (RPCB *)arg;
#ifdef RPCBIND_DEBUG
	if (debugging) {
		char *uaddr;

		uaddr =	taddr2uaddr(rpcbind_get_conf(transp->xp_netid),
			    svc_getrpccaller(transp));
		fprintf(stderr, "RPCB_GETADDR req for (%lu, %lu, %s) from %s: ",
		    (unsigned long)regp->r_prog, (unsigned long)regp->r_vers,
		    regp->r_netid, uaddr);
		free(uaddr);
	}
#endif
	return (rpcbproc_getaddr_com(regp, rqstp, transp, RPCBVERS4,
					RPCB_ALLVERS));
}
Esempio n. 5
0
/*
 * rpcb_check; the rpcbind/portmap access check function.
 */
boolean_t
rpcb_check(SVCXPRT *transp, rpcproc_t procnum, boolean_t ispmap)
{
    struct netconfig *conf;
    boolean_t res = B_TRUE;

    if ((conf = rpcbind_get_conf(transp->xp_netid)) == 0) {
        syslog(LOG_ERR,
               "rpcbind_get_conf failed: no client address checks");
        return (B_TRUE);
    }

    /*
     * Require IPv4 for pmap calls; they're not defined for anything else.
     */
    if (ispmap && strcmp(conf->nc_protofmly, "inet") != 0) {
        res = B_FALSE;
    } else if (strcmp(conf->nc_protofmly, "inet") == 0 ||
               strcmp(conf->nc_protofmly, "inet6") == 0) {
        const char *addr_string = sgen_toa(svc_getgencaller(transp));

        if (!localxprt(transp, ispmap) &&
                (local_only ||
                 hosts_ctl("rpcbind", addr_string, addr_string, "") == 0)) {
            res = B_FALSE;
        }
    }
out:
    if (!res)
        svcerr_auth(transp, AUTH_FAILED);

    if (verboselog || !res)
        rpcb_log(res, transp, procnum, 0, ispmap);

    return (res);
}
Esempio n. 6
0
/* ARGSUSED */
static void *
rpcbproc_getaddrlist_4_local(void *arg, struct svc_req *rqstp /*__unused*/,
			     SVCXPRT *transp, rpcvers_t versnum /*__unused*/)
{
	RPCB *regp = (RPCB *)arg;
	static rpcb_entry_list_ptr rlist;
	register rpcblist_ptr rbl;
	rpcb_entry_list_ptr rp, tail;
	rpcprog_t prog;
	rpcvers_t vers;
	rpcb_entry *a;
	struct netconfig *nconf;
	struct netconfig *reg_nconf;
	char *saddr, *maddr = NULL;

	free_rpcb_entry_list(&rlist);
	tail = NULL;
	prog = regp->r_prog;
	vers = regp->r_vers;
	reg_nconf = rpcbind_get_conf(transp->xp_netid);
	if (reg_nconf == NULL)
		return (NULL);
	if (*(regp->r_addr) != '\0') {
		saddr = regp->r_addr;
	} else {
		saddr = NULL;
	}
#ifdef RPCBIND_DEBUG
	if (debugging) {
		fprintf(stderr, "r_addr: %s r_netid: %s nc_protofmly: %s\n",
		    regp->r_addr, regp->r_netid, reg_nconf->nc_protofmly);
	}
#endif
	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
	    if ((rbl->rpcb_map.r_prog == prog) &&
		(rbl->rpcb_map.r_vers == vers)) {
		nconf = rpcbind_get_conf(rbl->rpcb_map.r_netid);
		if (nconf == NULL)
			goto fail;
		if (strcmp(nconf->nc_protofmly, reg_nconf->nc_protofmly)
				!= 0) {
			continue;	/* not same proto family */
		}
#ifdef RPCBIND_DEBUG
		if (debugging)
			fprintf(stderr, "\tmerge with: %s\n",
			    rbl->rpcb_map.r_addr);
#endif
		if ((maddr = mergeaddr(transp, rbl->rpcb_map.r_netid,
				rbl->rpcb_map.r_addr, saddr)) == NULL) {
#ifdef RPCBIND_DEBUG
		if (debugging)
			fprintf(stderr, " FAILED\n");
#endif
			continue;
		} else if (!maddr[0]) {
#ifdef RPCBIND_DEBUG
	if (debugging)
		fprintf(stderr, " SUCCEEDED, but port died -  maddr: nullstring\n");
#endif
			/* The server died. Unset this combination */
			delete_prog(regp->r_prog);
			continue;
		}
#ifdef RPCBIND_DEBUG
		if (debugging)
			fprintf(stderr, " SUCCEEDED maddr: %s\n", maddr);
#endif
		/*
		 * Add it to rlist.
		 */
		rp = malloc(sizeof (rpcb_entry_list));
		if (rp == NULL)
			goto fail;
		a = &rp->rpcb_entry_map;
		a->r_maddr = maddr;
		a->r_nc_netid = nconf->nc_netid;
		a->r_nc_semantics = nconf->nc_semantics;
		a->r_nc_protofmly = nconf->nc_protofmly;
		a->r_nc_proto = nconf->nc_proto;
		rp->rpcb_entry_next = NULL;
		if (rlist == NULL) {
			rlist = rp;
			tail = rp;
		} else {
			tail->rpcb_entry_next = rp;
			tail = rp;
		}
		rp = NULL;
	    }
	}
#ifdef RPCBIND_DEBUG
	if (debugging) {
		for (rp = rlist; rp; rp = rp->rpcb_entry_next) {
			fprintf(stderr, "\t%s %s\n", rp->rpcb_entry_map.r_maddr,
				rp->rpcb_entry_map.r_nc_proto);
		}
	}
#endif
	/*
	 * XXX: getaddrlist info is also being stuffed into getaddr.
	 * Perhaps wrong, but better than it not getting counted at all.
	 */
	rpcbs_getaddr(RPCBVERS4 - 2, prog, vers, transp->xp_netid, maddr);
	return (void *)&rlist;

fail:	free_rpcb_entry_list(&rlist);
	return (NULL);
}
Esempio n. 7
0
/*
 * Find a server address that can be used by `caller' to contact
 * the local service specified by `serv_uaddr'. If `clnt_uaddr' is
 * non-NULL, it is used instead of `caller' as a hint suggesting
 * the best address (e.g. the `r_addr' field of an rpc, which
 * contains the rpcbind server address that the caller used).
 *
 * Returns the best server address as a malloc'd "universal address"
 * string which should be freed by the caller. On error, returns NULL.
 */
char *
addrmerge(struct netbuf *caller, const char *serv_uaddr, const char *clnt_uaddr,
	  const char *netid)
{
	struct ifaddrs *ifap, *ifp = NULL, *bestif;
	struct netbuf *serv_nbp = NULL, *hint_nbp = NULL, tbuf;
	struct sockaddr *caller_sa, *hint_sa, *ifsa, *ifmasksa, *serv_sa;
	struct sockaddr_storage ss;
	struct netconfig *nconf;
	char *caller_uaddr = NULL;
	const char *hint_uaddr = NULL;
	char *ret = NULL;
	int bestif_goodness;

#ifdef ND_DEBUG
	if (debugging)
		fprintf(stderr, "addrmerge(caller, %s, %s, %s\n", serv_uaddr,
		    clnt_uaddr == NULL ? "NULL" : clnt_uaddr, netid);
#endif
	caller_sa = caller->buf;
	if ((nconf = rpcbind_get_conf(netid)) == NULL)
		goto freeit;
	if ((caller_uaddr = taddr2uaddr(nconf, caller)) == NULL)
		goto freeit;

	/*
	 * Use `clnt_uaddr' as the hint if non-NULL, but ignore it if its
	 * address family is different from that of the caller.
	 */
	hint_sa = NULL;
	if (clnt_uaddr != NULL) {
		hint_uaddr = clnt_uaddr;
		if ((hint_nbp = uaddr2taddr(nconf, clnt_uaddr)) == NULL)
			goto freeit;
		hint_sa = hint_nbp->buf;
	}
	if (hint_sa == NULL || hint_sa->sa_family != caller_sa->sa_family) {
		hint_uaddr = caller_uaddr;
		hint_sa = caller->buf;
	}

#ifdef ND_DEBUG
	if (debugging)
		fprintf(stderr, "addrmerge: hint %s\n", hint_uaddr);
#endif
	/* Local caller, just return the server address. */
	if (strncmp(caller_uaddr, "0.0.0.0.", 8) == 0 ||
	    strncmp(caller_uaddr, "::.", 3) == 0 || caller_uaddr[0] == '/') {
		ret = strdup(serv_uaddr);
		goto freeit;
	}

	if (getifaddrs(&ifp) < 0)
		goto freeit;

	/*
	 * Loop through all interface addresses.  We are listening to an address
	 * if any of the following are true:
	 * a) It's a loopback address
	 * b) It was specified with the -h command line option
	 * c) There were no -h command line options.
	 *
	 * Among addresses on which we are listening, choose in order of
	 * preference an address that is:
	 *
	 * a) Equal to the hint
	 * b) A link local address with the same scope ID as the client's
	 *    address, if the client's address is also link local
	 * c) An address on the same subnet as the client's address
	 * d) A non-localhost, non-p2p address
	 * e) Any usable address
	 */
	bestif = NULL;
	bestif_goodness = 0;
	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
		ifsa = ifap->ifa_addr;
		ifmasksa = ifap->ifa_netmask;

		/* Skip addresses where we don't listen */
		if (ifsa == NULL || ifsa->sa_family != hint_sa->sa_family ||
		    !(ifap->ifa_flags & IFF_UP))
			continue;

		if (!(ifap->ifa_flags & IFF_LOOPBACK) && !listen_addr(ifsa))
			continue;

		if ((hint_sa->sa_family == AF_INET) &&
		    ((((struct sockaddr_in*)hint_sa)->sin_addr.s_addr == 
		      ((struct sockaddr_in*)ifsa)->sin_addr.s_addr))) {
			const int goodness = 4;

			bestif_goodness = goodness;
			bestif = ifap;
			goto found;
		}
#ifdef INET6
		if ((hint_sa->sa_family == AF_INET6) &&
		    (0 == memcmp(&((struct sockaddr_in6*)hint_sa)->sin6_addr,
				 &((struct sockaddr_in6*)ifsa)->sin6_addr,
				 sizeof(struct in6_addr))) &&
		    (((struct sockaddr_in6*)hint_sa)->sin6_scope_id ==
		    (((struct sockaddr_in6*)ifsa)->sin6_scope_id))) {
			const int goodness = 4;

			bestif_goodness = goodness;
			bestif = ifap;
			goto found;
		}
		if (hint_sa->sa_family == AF_INET6) {
			/*
			 * For v6 link local addresses, if the caller is on
			 * a link-local address then use the scope id to see
			 * which one.
			 */
			if (IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(ifsa)) &&
			    IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(caller_sa)) &&
			    IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(hint_sa))) {
				if (SA2SIN6(ifsa)->sin6_scope_id ==
				    SA2SIN6(caller_sa)->sin6_scope_id) {
					const int goodness = 3;

					if (bestif_goodness < goodness) {
						bestif = ifap;
						bestif_goodness = goodness;
					}
				}
			}
		}
#endif /* INET6 */
		if (0 == bitmaskcmp(hint_sa, ifsa, ifmasksa)) {
			const int goodness = 2;

			if (bestif_goodness < goodness) {
				bestif = ifap;
				bestif_goodness = goodness;
			}
		}
		if (!(ifap->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
			const int goodness = 1;

			if (bestif_goodness < goodness) {
				bestif = ifap;
				bestif_goodness = goodness;
			}
		}
		if (bestif == NULL)
			bestif = ifap;
	}
	if (bestif == NULL)
		goto freeit;

found:
	/*
	 * Construct the new address using the address from
	 * `bestif', and the port number from `serv_uaddr'.
	 */
	serv_nbp = uaddr2taddr(nconf, serv_uaddr);
	if (serv_nbp == NULL)
		goto freeit;
	serv_sa = serv_nbp->buf;

	memcpy(&ss, bestif->ifa_addr, bestif->ifa_addr->sa_len);
	switch (ss.ss_family) {
	case AF_INET:
		SA2SIN(&ss)->sin_port = SA2SIN(serv_sa)->sin_port;
		break;
#ifdef INET6
	case AF_INET6:
		SA2SIN6(&ss)->sin6_port = SA2SIN6(serv_sa)->sin6_port;
		break;
#endif
	}
	tbuf.len = ss.ss_len;
	tbuf.maxlen = sizeof(ss);
	tbuf.buf = &ss;
	ret = taddr2uaddr(nconf, &tbuf);

freeit:
	if (caller_uaddr != NULL)
		free(caller_uaddr);
	if (hint_nbp != NULL) {
		free(hint_nbp->buf);
		free(hint_nbp);
	}
	if (serv_nbp != NULL) {
		free(serv_nbp->buf);
		free(serv_nbp);
	}
	if (ifp != NULL)
		freeifaddrs(ifp);

#ifdef ND_DEBUG
	if (debugging)
		fprintf(stderr, "addrmerge: returning %s\n", ret);
#endif
	return ret;
}
Esempio n. 8
0
	RPCB *regp = (RPCB *)arg;
	static rpcb_entry_list_ptr rlist;
	register rpcblist_ptr rbl;
	rpcb_entry_list_ptr rp, tail;
	rpcprog_t prog;
	rpcvers_t vers;
	rpcb_entry *a;
	struct netconfig *nconf;
	struct netconfig *reg_nconf;
	char *saddr, *maddr = NULL;

	free_rpcb_entry_list(&rlist);
	tail = NULL;
	prog = regp->r_prog;
	vers = regp->r_vers;
	reg_nconf = rpcbind_get_conf(transp->xp_netid);
	if (reg_nconf == NULL)
		return (NULL);
	if (*(regp->r_addr) != '\0') {
		saddr = regp->r_addr;
	} else {
		saddr = NULL;
	}
#ifdef RPCBIND_DEBUG
	if (debugging) {
		fprintf(stderr, "r_addr: %s r_netid: %s nc_protofmly: %s\n",
		    regp->r_addr, regp->r_netid, reg_nconf->nc_protofmly);
	}
#endif
	for (rbl = list_rbl; rbl != NULL; rbl = rbl->rpcb_next) {
	    if ((rbl->rpcb_map.r_prog == prog) &&
Esempio n. 9
0
bool_t
rpcbproc_callit_com(rpcb_rmtcallargs *a, void *result, 
		    ar_svc_req_t *rqstp, arpcvers_t versnum)
{
	rpcblist_ptr rbl;
	ar_netid_t *nconf;
	ar_svc_xprt_t *transp;
	char *uaddr, *m_uaddr = NULL, *local_uaddr = NULL;
	arpcproc_t reply_type;
	arpc_createerr_t cerr;
	struct sockaddr_storage ss;
	struct sockaddr *localsa;
	const char *netidstr;
	struct timespec tlimit;
	arpc_addr_t caller;
	arpc_addr_t tbuf;
	arpc_addr_t *na;
	char *errstr;
	struct finfo *info;
	int err;

	caller.maxlen = sizeof(ss);
	caller.len = sizeof(ss);
	caller.buf = (char *)&ss;

	reply_type = rqstp->rq_proc;
	transp = rqstp->rq_xprt;

	if (!ar_svc_control(rqstp->rq_xprt,  AR_SVCGET_NETID, &netidstr)) {
		ar_svcflgerr_systemerr(rqstp);
		return FALSE;
	}

	if (!check_callit(rqstp, a, versnum)) {
		ar_svcflgerr_weakauth(rqstp);
		return FALSE;
	}

	if (!ar_svc_control(rqstp->rq_xprt, AR_SVCGET_REMOTE_ADDR, &caller)) {
		ar_svcflgerr_systemerr(rqstp);
		return FALSE;
	}
		
#ifdef RPCBIND_DEBUG
	if (debugging) {
		uaddr = rqst2uaddr(rqstp);
		fprintf(stderr, "%s %s req for (%lu, %lu, %lu, %s) from %s : ",
			versnum == PMAPVERS ? "pmap_rmtcall" :
			versnum == RPCBVERS ? "rpcb_rmtcall" :
			versnum == RPCBVERS4 ? "rpcb_indirect" : "unknown",
			reply_type == RPCBPROC_INDIRECT ? "indirect" : 
			"callit",
			(unsigned long)a->rmt_prog, (unsigned long)a->rmt_vers,
			(unsigned long)a->rmt_proc, netidstr,
			uaddr ? uaddr : "unknown");
		if (uaddr) {
			free(uaddr);
		}
		uaddr = NULL;
	}
#endif
	rbl = find_service(a->prog, a->vers, netidstr);

	rpcbs_rmtcall(versnum - 2, reply_type, a->prog, a->vers,
		      a->proc, netidstr, rbl);

	if (rbl == (rpcblist_ptr)NULL) {
#ifdef RPCBIND_DEBUG
		if (debugging) {
			fprintf(stderr, "not found\n");
		}
#endif
		if (reply_type == RPCBPROC_INDIRECT) {
			ar_svcflgerr_noprog(rqstp);
		}
		return FALSE;
	}
	if (rbl->rpcb_map.r_vers != a->vers) {
		if (reply_type == RPCBPROC_INDIRECT) {
			arpcvers_t vers_low, vers_high;

			find_versions(a->prog, netidstr,
				      &vers_low, &vers_high);
			ar_svcflgerr_progvers(rqstp, vers_low, vers_high);
		}
		return FALSE;
	}

#ifdef RPCBIND_DEBUG
	if (debugging) {
		fprintf(stderr, "found at uaddr %s\n", rbl->rpcb_map.r_addr);
	}
#endif
	/*
	 *	Check whether this entry is valid and a server is present
	 *	Mergeaddr() returns NULL if no such entry is present, and
	 *	returns "" if the entry was present but the server is not
	 *	present (i.e., it crashed).
	 */
	if (reply_type == RPCBPROC_INDIRECT) {
		uaddr = mergeaddr(transp, netidstr, 
				  rbl->rpcb_map.r_addr, NULL);
		if (uaddr == NULL || uaddr[0] == '\0') {
			ar_svcflgerr_noprog(rqstp);
			if (uaddr != NULL) {
				free(uaddr);
			}
			uaddr = NULL;
			return FALSE;
		}
		free(uaddr);
		uaddr = NULL;
	}
	nconf = rpcbind_get_conf(netidstr);
	if (nconf == (ar_netid_t *)NULL) {
		if (reply_type == RPCBPROC_INDIRECT) {
			ar_svcflgerr_systemerr(rqstp);
			return FALSE;
		}
		if (debugging) {
			fprintf(stderr, "rpcbproc_callit_com:  "
				"rpcbind_get_conf failed\n");
		}
		return FALSE;
	}

	/* compute local_uaddr with merge (picks port from rbl, local address
	 * that most matches the request's src addr.
	 * 
	 * convert that back to uaddr
	 */

	localsa = local_sa(nconf->an_family, &tbuf.len);
	if (localsa == NULL) {
		if (debugging) {
			fprintf(stderr,
			"rpcbproc_callit_com: no local address\n");
		}
		goto error;
	}
	tbuf.maxlen = tbuf.len;
	tbuf.buf = (char *)localsa;
	local_uaddr = addrmerge(&tbuf, rbl->rpcb_map.r_addr, NULL, netidstr);
	if (!local_uaddr) {
		err = ENOMEM;
		goto error;
	}

	m_uaddr = addrmerge(&caller, rbl->rpcb_map.r_addr, NULL, netidstr);
	if (!m_uaddr) {
		err = ENOMEM;
		goto error;
	}

	err = ar_uaddr2taddr(rpcbind_ioctx, netidstr, local_uaddr, &na);
	if (err != 0) {
		if (reply_type == RPCBPROC_INDIRECT) {
			ar_svcflgerr_systemerr(rqstp);
		}
		goto error;
	}

	/* allocate forward table entry */
	err = forward_register(&info);
	if (err != 0) {
		goto error;
	}

	info->clnt = NULL;
	info->cco = NULL;
	info->sco = NULL;
	info->uaddr = m_uaddr;
	m_uaddr = NULL;

	/* setup/connect clnt. ar_clnt_tli_create() */
	err = ar_clnt_tli_create(rpcbind_ioctx, netidstr, na, 
				 a->prog, a->vers, NULL, &cerr,
				 &info->clnt);
	if (err != 0) {
		if (debugging) {
			errstr = ar_astrcreateerror(&cerr);
			if (errstr) {
				fprintf(stderr, "create clnt failed: %s\n",
					errstr);
				free(errstr);
			}
		}
		goto error;
	}

	tlimit.tv_sec = MAXTIME_OFF;
	tlimit.tv_nsec = 0;
	
	/* issue async rpc through clnt ar_clnt_call_async_copy */
	err = ar_clnt_call_async_copy(info->clnt, a->proc, 
				      (axdrproc_t)&axdr_callit_rmtcallargs,
				      a, (axdrproc_t)&axdr_callit_rmtresult, 
				      sizeof(rpcb_remote_result_t),
				      &rpcb_callit_done, info,
				      &tlimit, &info->cco);
	if (err != 0) {
		goto error;
	}

	/* call is running. Mark original server call as async so we
	 * can finish it when we get the result.
	 */
	err = ar_svc_async(rqstp, &info->sco);
	if (err != 0) {
		goto error;
	}

	/* done */
	info = NULL;
	err = 0;

error:
	if (err != 0 && reply_type == RPCBPROC_INDIRECT) {
		ar_svcflgerr_systemerr(rqstp);
	}

	if (local_uaddr) {
		free(local_uaddr);
		local_uaddr = NULL;
	}
	if (m_uaddr) {
		free(m_uaddr);
		m_uaddr = NULL;
	}

	if (na) {
		if (na->buf) {
			free(na->buf);
		}
		na->buf = NULL;
		free(na);
		na = NULL;
	}
	if (info) {
		if (info->cco) {
			ar_clnt_call_cancel(info->cco);
		}
		info->cco = NULL;
		if (info->sco) {
			ar_svc_async_done(info->sco, err);
		}
		info->sco = NULL;
		if (info->clnt) {
			ar_clnt_destroy(info->clnt);
		}
		info->clnt = NULL;
		if (info->uaddr) {
			free(info->uaddr);
		}
		info->uaddr = NULL;
		info->flag &= ~FINFO_ACTIVE;
		info = NULL;
	}
		
	return FALSE;
}