/* * This implements the yp "match" function. */ void ypmatch(SVCXPRT *transp, struct svc_req *rqstp) { struct ypreq_key req; struct ypresp_val resp; char *fun = "ypmatch"; DBM *fdb; memset(&req, 0, sizeof (req)); memset(&resp, 0, sizeof (resp)); resp.status = (unsigned)YP_NOKEY; if (!svc_getargs(transp, (xdrproc_t)xdr_ypreq_key, (char *)&req)) { svcerr_decode(transp); return; } /* * sanity check the map name and to a DBM lookup * also perform an access check... */ if ((fdb = ypset_current_map(req.map, req.domain, &resp.status)) != NULL && yp_map_access(transp, &resp.status, fdb)) { /* Check with the DBM database */ resp.valdat = dbm_fetch(fdb, req.keydat); if (resp.valdat.dptr != NULL) { resp.status = YP_TRUE; if (!silent) printf("%s: dbm: %40.40s\n", fun, resp.valdat.dptr); goto send_reply; } /* * If we're being asked to match YP_SECURE or YP_INTERDOMAIN * and we haven't found it in the dbm file, then we don't * really want to waste any more time. Specifically, we don't * want to ask DNS */ if (req.keydat.dsize == 0 || req.keydat.dptr == NULL || req.keydat.dptr[0] == '\0' || strncmp(req.keydat.dptr, yp_secure, req.keydat.dsize) == 0 || strncmp(req.keydat.dptr, yp_interdomain, req.keydat.dsize) == 0) { goto send_reply; } /* Let's try the YP_MULTI_ hack... */ #ifdef MINUS_C_OPTION if (multiflag == TRUE && multihomed(req, &resp, transp, fdb)) goto send_reply; #else if (multihomed(req, &resp, transp, fdb)) goto send_reply; #endif /* * Let's try DNS, but if client_setup_failure is set, * we have tried DNS in the past and failed, there is * no reason in forcing an infinite loop by turning * off DNS in setup_resolv() only to turn it back on * again here. */ if (!dnsforward && !client_setup_failure) { datum idkey, idval; idkey.dptr = yp_interdomain; idkey.dsize = yp_interdomain_sz; idval = dbm_fetch(fdb, idkey); if (idval.dptr) dnsforward = TRUE; } if (dnsforward) { if (!resolv_pid || !resolv_client) { setup_resolv(&dnsforward, &resolv_pid, &resolv_client, resolv_tp, 0); if (resolv_client == NULL) client_setup_failure = TRUE; } if (resolv_req(&dnsforward, &resolv_client, &resolv_pid, resolv_tp, rqstp->rq_xprt, &req, req.map) == TRUE) goto free_args; } } send_reply: if (!svc_sendreply(transp, (xdrproc_t)xdr_ypresp_val, (caddr_t)&resp)) { RESPOND_ERR; } free_args: if (!svc_freeargs(transp, (xdrproc_t)xdr_ypreq_key, (char *)&req)) { FREE_ERR; } }
/* V1 dispatch routines */ void ypoldmatch(SVCXPRT *transp, struct svc_req *rqstp) { bool dbmop_ok = TRUE; struct yprequest req; struct ypreq_key nrq; struct ypresponse resp; char *fun = "ypoldmatch"; DBM *fdb; memset((void *) &req, 0, sizeof (req)); memset((void *) &resp, 0, sizeof (resp)); if (!svc_getargs(transp, (xdrproc_t)_xdr_yprequest, (caddr_t)&req)) { svcerr_decode(transp); return; } if (req.yp_reqtype != YPMATCH_REQTYPE) { resp.ypmatch_resp_status = (unsigned)YP_BADARGS; dbmop_ok = FALSE; } if (dbmop_ok && (((fdb = ypset_current_map(req.ypmatch_req_map, req.ypmatch_req_domain, &resp.ypmatch_resp_status)) != NULL) && yp_map_access(transp, &resp.ypmatch_resp_status, fdb))) { /* Check with the DBM database */ resp.ypmatch_resp_valdat = dbm_fetch(fdb, req.ypmatch_req_keydat); if (resp.ypmatch_resp_valptr != NULL) { resp.ypmatch_resp_status = YP_TRUE; if (!silent) printf("%s: dbm: %s\n", fun, resp.ypmatch_resp_valptr); goto send_oldreply; } /* * If we're being asked to match YP_SECURE or YP_INTERDOMAIN * and we haven't found it in the dbm file, then we don't * really want to waste any more time. Specifically, we don't * want to ask DNS */ if (req.ypmatch_req_keysize == 0 || req.ypmatch_req_keyptr == NULL || req.ypmatch_req_keyptr[0] == '\0' || strncmp(req.ypmatch_req_keyptr, "YP_SECURE", 9) == 0 || strncmp(req.ypmatch_req_keyptr, "YP_INTERDOMAIN", 14) == 0) goto send_oldreply; /* Let's try the YP_MULTI_ hack... */ #ifdef MINUS_C_OPTION if (multiflag == TRUE && omultihomed(req, &resp, transp, fdb)) goto send_oldreply; #else if (omultihomed(req, &resp, transp, fdb)) goto send_oldreply; #endif /* Let's try DNS */ if (!dnsforward) { USE_YP_INTERDOMAIN datum idkey, idval; idkey.dptr = yp_interdomain; idkey.dsize = yp_interdomain_sz; idval = dbm_fetch(fdb, idkey); if (idval.dptr) dnsforward = TRUE; } if (dnsforward) { if (!resolv_pid) setup_resolv(&dnsforward, &resolv_pid, &resolv_client, resolv_tp, 0); if (req.yp_reqtype == YPREQ_KEY) { nrq = req.yp_reqbody.yp_req_keytype; resolv_req(&dnsforward, &resolv_client, &resolv_pid, resolv_tp, rqstp->rq_xprt, &nrq, nrq.map); } return; } } send_oldreply: if (!svc_sendreply(transp, (xdrproc_t)_xdr_ypresponse, (caddr_t)&resp)) { RESPOND_ERR; } if (!svc_freeargs(transp, (xdrproc_t)_xdr_yprequest, (char *)&req)) { FREE_ERR; } }
int resolv_req(bool *fwding, CLIENT **client, int *pid, char *tp, SVCXPRT *xprt, struct ypreq_key *req, char *map) { enum clnt_stat stat; struct timeval tv; struct ypfwdreq_key4 fwd_req4; struct ypfwdreq_key6 fwd_req6; struct in6_addr in6; int byname, byaddr; int byname_v6, byaddr_v6; #ifdef TDRPC struct sockaddr_in *addrp; #else struct netbuf *nb; char *uaddr; char *cp; int i; sa_family_t caller_af = AF_UNSPEC; struct sockaddr_in *sin4; struct sockaddr_in6 *sin6; #endif if (! *fwding) return (FALSE); byname = strcmp(map, "hosts.byname") == 0; byaddr = strcmp(map, "hosts.byaddr") == 0; byname_v6 = strcmp(map, "ipnodes.byname") == 0; byaddr_v6 = strcmp(map, "ipnodes.byaddr") == 0; if ((!byname && !byaddr && !byname_v6 && !byaddr_v6) || req->keydat.dsize == 0 || req->keydat.dptr[0] == '\0' || !isascii(req->keydat.dptr[0]) || !isgraph(req->keydat.dptr[0])) { /* default status is YP_NOKEY */ return (FALSE); } #ifdef TDRPC fwd_req4.map = map; fwd_req4.keydat = req->keydat; fwd_req4.xid = svc_getxid(xprt); addrp = svc_getcaller(xprt); fwd_req4.ip = addrp->sin_addr.s_addr; fwd_req4.port = addrp->sin_port; #else /* * In order to tell if we have an IPv4 or IPv6 caller address, * we must know that nb->buf is a (sockaddr_in *) or a * (sockaddr_in6 *). Hence, we might as well dispense with the * conversion to uaddr and parsing of same that this section * of the code previously involved itself in. */ nb = svc_getrpccaller(xprt); if (nb != 0) caller_af = ((struct sockaddr_storage *)nb->buf)->ss_family; if (caller_af == AF_INET6) { fwd_req6.map = map; fwd_req6.keydat = req->keydat; fwd_req6.xid = svc_getxid(xprt); sin6 = (struct sockaddr_in6 *)nb->buf; fwd_req6.addr = (uint32_t *)&in6; memcpy(fwd_req6.addr, sin6->sin6_addr.s6_addr, sizeof (in6)); fwd_req6.port = ntohs(sin6->sin6_port); } else if (caller_af == AF_INET) { fwd_req4.map = map; fwd_req4.keydat = req->keydat; fwd_req4.xid = svc_getxid(xprt); sin4 = (struct sockaddr_in *)nb->buf; fwd_req4.ip = ntohl(sin4->sin_addr.s_addr); fwd_req4.port = ntohs(sin4->sin_port); } else { syslog(LOG_ERR, "unknown caller IP address family %d", caller_af); return (FALSE); } #endif /* Restart resolver if it died. (possible overkill) */ if (kill(*pid, 0)) { syslog(LOG_INFO, "Restarting resolv server: old one (pid %d) died.\n", *pid); if (*client != NULL) clnt_destroy (*client); setup_resolv(fwding, pid, client, tp, 0 /* transient p# */); if (!*fwding) { syslog(LOG_ERR, "can't restart resolver: ending resolv service.\n"); return (FALSE); } } /* may need to up timeout */ tv.tv_sec = 10; tv.tv_usec = 0; if (caller_af == AF_INET6) { stat = clnt_call(*client, YPDNSPROC6, xdr_ypfwdreq_key6, (char *)&fwd_req6, xdr_void, 0, tv); } else { stat = clnt_call(*client, YPDNSPROC4, xdr_ypfwdreq_key4, (char *)&fwd_req4, xdr_void, 0, tv); } if (stat == RPC_SUCCESS) /* expected */ return (TRUE); else { /* Over kill error recovery */ /* make one attempt to restart service before turning off */ syslog(LOG_INFO, "Restarting resolv server: old one not responding.\n"); if (!kill(*pid, 0)) kill (*pid, SIGINT); /* cleanup old one */ if (*client != NULL) clnt_destroy (*client); setup_resolv(fwding, pid, client, tp, 0 /* transient p# */); if (!*fwding) { syslog(LOG_ERR, "can't restart resolver: ending resolv service.\n"); return (FALSE); } if (caller_af == AF_INET6) { stat = clnt_call(*client, YPDNSPROC6, xdr_ypfwdreq_key6, (char *)&fwd_req6, xdr_void, 0, tv); } else { stat = clnt_call(*client, YPDNSPROC4, xdr_ypfwdreq_key4, (char *)&fwd_req4, xdr_void, 0, tv); } if (stat == RPC_SUCCESS) /* expected */ return (TRUE); else { /* no more restarts */ clnt_destroy (*client); *fwding = FALSE; /* turn off fwd'ing */ syslog(LOG_ERR, "restarted resolver not responding: ending resolv service.\n"); return (FALSE); } } }