]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/statd/monitor.c
nfsidmap: Added Error Logging
[nfs-utils.git] / utils / statd / monitor.c
index f818b2b4ae69d38f282845887853ddcb53695b74..286a5e21e173442c6445f109ffe82765ea4bfdaf 100644 (file)
@@ -21,8 +21,8 @@
 #include <arpa/inet.h>
 #include <dirent.h>
 
+#include "sockaddr.h"
 #include "rpcmisc.h"
-#include "misc.h"
 #include "nsm.h"
 #include "statd.h"
 #include "notlist.h"
@@ -33,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;
 }
 
 /*
@@ -65,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);
 
@@ -108,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 */
@@ -123,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
@@ -145,7 +145,7 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
        clnt = rtnl;
 
        while ((clnt = nlist_gethost(clnt, mon_name, 0))) {
-               if (matchhostname(NL_MY_NAME(clnt), my_name) &&
+               if (statd_matchhostname(NL_MY_NAME(clnt), my_name) &&
                    NL_MY_PROC(clnt) == id->my_proc &&
                    NL_MY_PROG(clnt) == id->my_prog &&
                    NL_MY_VERS(clnt) == id->my_vers &&
@@ -157,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);
@@ -167,11 +168,11 @@ 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;
        }
 
-       NL_ADDR(clnt) = my_addr.sin_addr;
        NL_MY_PROG(clnt) = id->my_prog;
        NL_MY_VERS(clnt) = id->my_vers;
        NL_MY_PROC(clnt) = id->my_proc;
@@ -212,11 +213,11 @@ failure:
 }
 
 static unsigned int
-load_one_host(const char *hostname, const struct sockaddr *sap,
+load_one_host(const char *hostname,
+               __attribute__ ((unused)) const struct sockaddr *sap,
                const struct mon *m,
                __attribute__ ((unused)) const time_t timestamp)
 {
-       const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
        notify_list *clnt;
 
        clnt = nlist_new(m->mon_id.my_id.my_name,
@@ -233,7 +234,6 @@ load_one_host(const char *hostname, const struct sockaddr *sap,
        xlog(D_GENERAL, "Adding record for %s to the monitor list...",
                        hostname);
 
-       NL_ADDR(clnt) = sin->sin_addr;
        NL_MY_PROG(clnt) = m->mon_id.my_id.my_prog;
        NL_MY_VERS(clnt) = m->mon_id.my_id.my_vers;
        NL_MY_PROC(clnt) = m->mon_id.my_id.my_proc;
@@ -249,7 +249,7 @@ void load_state(void)
 
        count = nsm_load_monitor_list(load_one_host);
        if (count)
-               xlog(D_GENERAL, "Loaded %u previously monitored hosts");
+               xlog(D_GENERAL, "Loaded %u previously monitored hosts", count);
 }
 
 /*
@@ -298,7 +298,7 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
         * entry winds up in the list the way I'm currently handling them.)
         */
        while ((clnt = nlist_gethost(clnt, mon_name, 0))) {
-               if (matchhostname(NL_MY_NAME(clnt), my_name) &&
+               if (statd_matchhostname(NL_MY_NAME(clnt), my_name) &&
                        NL_MY_PROC(clnt) == id->my_proc &&
                        NL_MY_PROG(clnt) == id->my_prog &&
                        NL_MY_VERS(clnt) == id->my_vers) {
@@ -309,7 +309,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);
@@ -363,7 +364,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;