X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=utils%2Fstatd%2Fmonitor.c;h=11afe0839e9a991037e6788e0b22efbd84b0a482;hb=17d144b236c84150c2ca896c0d3eea05931d938e;hp=51075b591de58d468835ba0ca13cb9d192da8416;hpb=cbd3a131e5c02bbd7b92a72b3ac467d71cfee1c4;p=nfs-utils.git diff --git a/utils/statd/monitor.c b/utils/statd/monitor.c index 51075b5..11afe08 100644 --- a/utils/statd/monitor.c +++ b/utils/statd/monitor.c @@ -21,6 +21,7 @@ #include #include +#include "sockaddr.h" #include "rpcmisc.h" #include "nsm.h" #include "statd.h" @@ -32,20 +33,26 @@ notify_list * rtnl = NULL; /* Run-time notify list. */ /* * Reject requests from non-loopback addresses in order * to prevent attack described in CERT CA-99.05. + * + * Although the kernel contacts the statd service via only IPv4 + * transports, the statd service can receive other requests, such + * as SM_NOTIFY, from remote peers via IPv6. */ -static int +static _Bool caller_is_localhost(struct svc_req *rqstp) { - struct sockaddr_in *sin = nfs_getrpccaller_in(rqstp->rq_xprt); - struct in_addr caller; - - caller = sin->sin_addr; - if (caller.s_addr != htonl(INADDR_LOOPBACK)) { - xlog_warn("Call to statd from non-local host %s", - inet_ntoa(caller)); - return 0; - } - return 1; + struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt); + char buf[INET6_ADDRSTRLEN]; + + if (!nfs_is_v4_loopback(sap)) + goto out_nonlocal; + return true; + +out_nonlocal: + if (!statd_present_address(sap, buf, sizeof(buf))) + buf[0] = '\0'; + xlog_warn("SM_MON/SM_UNMON call from non-local host %s", buf); + return false; } /* @@ -64,8 +71,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) .sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK), }; - char *dnsname; - struct hostent *hostinfo = NULL; + char *dnsname = NULL; xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name); @@ -107,9 +113,6 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) "or starting '.': %s", mon_name); xlog(L_ERROR, "POSSIBLE SPOOF/ATTACK ATTEMPT!"); goto failure; - } else if ((hostinfo = gethostbyname(mon_name)) == NULL) { - xlog_warn("gethostbyname error for %s", mon_name); - goto failure; } /* my_name must not have white space */ @@ -122,15 +125,13 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) * Now choose a hostname to use for matching. We cannot * really trust much in the incoming NOTIFY, so to make * sure that multi-homed hosts work nicely, we get an - * FQDN now, and use that for matching + * FQDN now, and use that for matching. */ - hostinfo = gethostbyaddr(hostinfo->h_addr, - hostinfo->h_length, - hostinfo->h_addrtype); - if (hostinfo) - dnsname = xstrdup(hostinfo->h_name); - else - dnsname = xstrdup(my_name); + dnsname = statd_canonical_name(mon_name); + if (dnsname == NULL) { + xlog(L_WARNING, "No canonical hostname found for %s", mon_name); + goto failure; + } /* Now check to see if this is a duplicate, and warn if so. * I will also return STAT_FAIL. (I *think* this is how I should @@ -156,6 +157,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) mon_name, my_name); /* But we'll let you pass anyway. */ + free(dnsname); goto success; } clnt = NL_NEXT(clnt); @@ -166,6 +168,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp) * doesn't fail. (I should probably fix this assumption.) */ if (!(clnt = nlist_new(my_name, mon_name, 0))) { + free(dnsname); xlog_warn("out of memory"); goto failure; } @@ -308,7 +311,8 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp) /* PRC: do the HA callout: */ ha_callout("del-client", mon_name, my_name, -1); - nsm_delete_monitored_host(clnt->dns_name); + nsm_delete_monitored_host(clnt->dns_name, + mon_name, my_name); nlist_free(&rtnl, clnt); return (&result); @@ -362,7 +366,8 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp) temp = NL_NEXT(clnt); /* PRC: do the HA callout: */ ha_callout("del-client", mon_name, my_name, -1); - nsm_delete_monitored_host(clnt->dns_name); + nsm_delete_monitored_host(clnt->dns_name, + mon_name, my_name); nlist_free(&rtnl, clnt); ++count; clnt = temp;