/* * 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); }
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; }