bool_t rpcbproc_getaddr_com(rpcb *regp, char **result, ar_svc_req_t *rqstp, arpcvers_t rpcbversnum, arpcvers_t verstype) { char *uaddr; char *saddr; const char *netidstr; rpcblist_ptr fnd; uaddr = NULL; saddr = NULL; if (!ar_svc_control(rqstp->rq_xprt, AR_SVCGET_NETID, &netidstr)) { ar_svcflgerr_systemerr(rqstp); return FALSE; } fnd = find_service(regp->r_prog, regp->r_vers, netidstr); if (fnd && ((verstype == RPCB_ALLVERS) || (regp->r_vers == fnd->rpcb_map.r_vers))) { if (*(regp->r_addr) != '\0') { /* may contain a hint about */ saddr = regp->r_addr; /* the interface that we */ } /* should use */ if (!(uaddr = mergeaddr(rqstp->rq_xprt, netidstr, fnd->rpcb_map.r_addr, saddr))) { /* Try whatever we have */ uaddr = strdup(fnd->rpcb_map.r_addr); } else if (!uaddr[0]) { /* * The server died. Unset all versions of this prog. */ delete_prog(regp->r_prog); uaddr = strdup(""); } } else { uaddr = strdup(""); } if (!uaddr) { ar_svcflgerr_systemerr(rqstp); return FALSE; } #ifdef RPCBIND_DEBUG if (debugging) { fprintf(stderr, "getaddr: %s\n", uaddr); } #endif /* XXX: should have used some defined constant here */ rpcbs_getaddr(rpcbversnum - 2, regp->r_prog, regp->r_vers, netidstr, uaddr); *result = uaddr; return TRUE; }
/* 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); }
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; }