Example #1
0
/*
 * Returns NULL if there was some system error.
 * Returns "" if the address was not bound, i.e the server crashed.
 * Returns the merged address otherwise.
 */
char *
mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
{
	struct fdlist *fdl;
	char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;

	for (fdl = fdhead; fdl; fdl = fdl->next)
		if (strcmp(fdl->nconf->nc_netid, netid) == 0)
			break;
	if (fdl == NULL)
		return (NULL);
	if (check_bound(fdl, uaddr) == FALSE)
		/* that server died */
		return strdup(emptystring);
	/*
	 * If saddr is not NULL, the remote client may have included the
	 * address by which it contacted us.  Use that for the "client" uaddr,
	 * otherwise use the info from the SVCXPRT.
	 */
	if (saddr != NULL) {
		c_uaddr = saddr;
	} else {
		c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
		if (c_uaddr == NULL) {
			syslog(LOG_ERR, "taddr2uaddr failed for %s",
				fdl->nconf->nc_netid);
			return (NULL);
		}
		allocated_uaddr = c_uaddr;
	}

#ifdef RPCBIND_DEBUG
	if (debugging) {
		if (saddr == NULL) {
			fprintf(stderr, "mergeaddr: client uaddr = %s\n",
			    c_uaddr);
		} else {
			fprintf(stderr, "mergeaddr: contact uaddr = %s\n",
			    c_uaddr);
		}
	}
#endif
	s_uaddr = uaddr;
	/*
	 * This is all we should need for IP 4 and 6
	 */
	m_uaddr = addrmerge(svc_getrpccaller(xprt), s_uaddr, c_uaddr, netid);
#ifdef RPCBIND_DEBUG
	if (debugging)
		fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
				uaddr, m_uaddr);
#endif
	if (allocated_uaddr != NULL)
		free(allocated_uaddr);
	return (m_uaddr);
}
Example #2
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;
}