]> git.saurik.com Git - apple/network_cmds.git/commitdiff
network_cmds-176.3.3.tar.gz mac-os-x-1035 v176.3.3
authorApple <opensource@apple.com>
Thu, 8 Jul 2004 21:24:02 +0000 (21:24 +0000)
committerApple <opensource@apple.com>
Thu, 8 Jul 2004 21:24:02 +0000 (21:24 +0000)
rpc_lockd.tproj/kern.c
rpc_lockd.tproj/lock_proc.c
rpc_lockd.tproj/lockd.c
rpc_lockd.tproj/lockd_lock.c
rpc_lockd.tproj/lockd_lock.h
rpc_statd.tproj/procs.c

index a231b87b6b44ba427bb3b503be08ea70e13b9ec4..eb29905f2b11d21359b626337ea878a362168b45 100644 (file)
@@ -357,6 +357,8 @@ lock_request(LOCKD_MSG *msg)
                    msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
                    from_addr((struct sockaddr *)&msg->lm_addr));
 
+       monitor_lock_host_by_addr((struct sockaddr *)&msg->lm_addr);
+
        if (msg->lm_flags & LOCKD_MSG_NFSV3) {
                arg4.cookie.n_bytes = (char *)&msg->lm_xid;
                arg4.cookie.n_len = sizeof(msg->lm_xid);
index 2029deb86bc1adc1a5fab037dc42775a3fd0bdfa..1ae97ef2025f66cc120061ff5cb174eab8da5831 100644 (file)
@@ -48,6 +48,8 @@ __RCSID("$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $");
 #include <stdio.h>
 #include <string.h>
 #include <syslog.h>
+#include <stdlib.h>
+#include <sys/queue.h>
 
 #include <rpc/rpc.h>
 #include <rpcsvc/sm_inter.h>
@@ -62,7 +64,6 @@ __RCSID("$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $");
 
 static void    log_from_addr(const char *, struct svc_req *);
 static void    log_netobj(netobj *obj);
-static int     addrcmp(struct sockaddr *, struct sockaddr *);
 
 /* log_from_addr ----------------------------------------------------------- */
 /*
@@ -156,10 +157,27 @@ static struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE];
 static rpcvers_t clnt_cache_vers[CLIENT_CACHE_SIZE];
 static int clnt_cache_next_to_use = 0;
 
-static int
-addrcmp(sa1, sa2)
-       struct sockaddr *sa1;
-       struct sockaddr *sa2;
+/*
+ * Because lockd is single-threaded, slow/unresponsive portmappers on
+ * clients can cause serious performance issues.  So, we keep a list of
+ * these bad hosts, and limit how often we try to get_client() for those hosts.
+ */
+struct badhost {
+       TAILQ_ENTRY(badhost) list;
+       struct sockaddr_storage addr;   /* host address */
+       int count;                      /* # of occurences */
+       time_t timelast;                /* last attempted */
+       time_t timenext;                /* next allowed */
+};
+TAILQ_HEAD(badhostlist_head, badhost);
+static struct badhostlist_head badhostlist_head = TAILQ_HEAD_INITIALIZER(badhostlist_head);
+#define        BADHOST_CLIENT_TOOK_TOO_LONG    5       /* In seconds */
+#define        BADHOST_INITIAL_DELAY           120     /* In seconds */
+#define        BADHOST_MAXIMUM_DELAY           3600    /* In seconds */
+#define        BADHOST_DELAY_INCREMENT         300     /* In seconds */
+
+int
+addrcmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
 {
        int len;
        void *p1, *p2;
@@ -190,82 +208,190 @@ get_client(host_addr, vers)
        struct sockaddr *host_addr;
        rpcvers_t vers;
 {
-       CLIENT *client;
+       CLIENT *client, *cached_client;
        struct timeval retry_time, time_now;
        int i;
        int sock_no;
+       time_t time_start, cache_time = 0;
+       struct badhost *badhost, *nextbadhost;
 
        gettimeofday(&time_now, NULL);
 
        /*
-        * Search for the given client in the cache, zapping any expired
-        * entries that we happen to notice in passing.
+        * Search for the given client in the cache.
         */
+       cached_client = NULL;
        for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
                client = clnt_cache_ptr[i];
-               if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
-                   < time_now.tv_sec)) {
-                       /* Cache entry has expired. */
-                       if (debug_level > 3)
-                               syslog(LOG_DEBUG, "Expired CLIENT* in cache");
-                       clnt_cache_time[i] = 0L;
-                       clnt_destroy(client);
-                       clnt_cache_ptr[i] = NULL;
-                       client = NULL;
-               }
-               if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i],
-                   host_addr) && clnt_cache_vers[i] == vers) {
-                       /* Found it! */
+               if (!client)
+                       continue;
+               if (clnt_cache_vers[i] != vers)
+                       continue;
+               if (addrcmp((struct sockaddr *)&clnt_cache_addr[i], host_addr))
+                       continue;
+               /* Found it! */
+               if (((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) > time_now.tv_sec)) {
                        if (debug_level > 3)
                                syslog(LOG_DEBUG, "Found CLIENT* in cache");
                        return (client);
                }
+               syslog(LOG_DEBUG, "Found expired CLIENT* in cache");
+               cached_client = client;
+               /* if we end up reusing this guy, make sure we keep the same timestamp */
+               cache_time = clnt_cache_time[i];
+               clnt_cache_time[i] = 0L;
+               clnt_cache_ptr[i] = NULL;
+               client = NULL;
+               break;
        }
 
-       if (debug_level > 3)
-               syslog(LOG_DEBUG, "CLIENT* not found in cache, creating");
+       /*
+        * Search for the given client in the badhost list.
+        */
+       badhost = TAILQ_FIRST(&badhostlist_head);
+       while (badhost) {
+               nextbadhost = TAILQ_NEXT(badhost, list);
+               if (!addrcmp(host_addr, (struct sockaddr *)&badhost->addr))
+                       break;
+               if ((badhost->timelast + BADHOST_MAXIMUM_DELAY) < time_now.tv_sec) {
+                       /* cleanup entries we haven't heard from in a while */
+                       TAILQ_REMOVE(&badhostlist_head, badhost, list);
+                       free(badhost);
+               }
+               badhost = nextbadhost;
+       }
 
-       /* Not found in cache.  Free the next entry if it is in use. */
+       if (badhost && (time_now.tv_sec < badhost->timenext)) {
+               /*
+                * We've got a badhost, and we don't want to try
+                * consulting it again yet.  If we've got a stale
+                * cached CLIENT*, go ahead and try to use that.
+                */
+               if (cached_client) {
+                       syslog(LOG_DEBUG, "badhost delayed: stale CLIENT* found in cache");
+                       /* Free the next entry if it is in use. */
+                       if (clnt_cache_ptr[clnt_cache_next_to_use]) {
+                               clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
+                               clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
+                       }
+                       client = cached_client;
+                       goto update_cache_entry;
+               }
+               syslog(LOG_DEBUG, "badhost delayed: valid CLIENT* not found in cache");
+               return NULL;
+       }
+
+       if (debug_level > 3) {
+               if (!cached_client)
+                       syslog(LOG_DEBUG, "CLIENT* not found in cache, creating");
+               else
+                       syslog(LOG_DEBUG, "stale CLIENT* found in cache, updating");
+       }
+
+       /* Free the next entry if it is in use. */
        if (clnt_cache_ptr[clnt_cache_next_to_use]) {
                clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
                clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
        }
 
        /* Create the new client handle                                       */
+       time_start = time_now.tv_sec;
 
        sock_no = RPC_ANYSOCK;
        retry_time.tv_sec = 5;
        retry_time.tv_usec = 0;
        ((struct sockaddr_in *)host_addr)->sin_port = 0;      /* Force consultation with portmapper   */
        client = clntudp_create((struct sockaddr_in *)host_addr, NLM_PROG, vers, retry_time, &sock_no);
+
+       gettimeofday(&time_now, NULL);
+       if (time_now.tv_sec - time_start >= BADHOST_CLIENT_TOOK_TOO_LONG) {
+               /*
+                * The client create took a long time!  (slow/unresponsive portmapper?)
+                * Add/update an entry in the badhost list.
+                */
+               if (!badhost && (badhost = malloc(sizeof(struct badhost)))) {
+                       /* allocate new badhost */
+                       memcpy(&badhost->addr, host_addr, host_addr->sa_len);
+                       badhost->count = 0;
+                       TAILQ_INSERT_TAIL(&badhostlist_head, badhost, list);
+               }
+               if (badhost) {
+                       /* update count and times */
+                       badhost->count++;
+                       badhost->timelast = time_now.tv_sec;
+                       if (badhost->count == 1) {
+                               /* first timers get a shorter initial delay */
+                               badhost->timenext = time_now.tv_sec + BADHOST_INITIAL_DELAY;
+                       } else {
+                               /* multiple offenders get an increasingly larger delay */
+                               int delay = (badhost->count - 1) * BADHOST_DELAY_INCREMENT;
+                               if (delay > BADHOST_MAXIMUM_DELAY)
+                                       delay = BADHOST_MAXIMUM_DELAY;
+                               badhost->timenext = time_now.tv_sec + delay;
+                       }
+                       /* move to end of list */
+                       TAILQ_REMOVE(&badhostlist_head, badhost, list);
+                       TAILQ_INSERT_TAIL(&badhostlist_head, badhost, list);
+               }
+       } else if (badhost) {
+               /* host seems good now, remove it from list */
+               TAILQ_REMOVE(&badhostlist_head, badhost, list);
+               free(badhost);
+               badhost = NULL;
+       }
+
        if (!client) { 
-               syslog(LOG_DEBUG, "%s", clnt_spcreateerror("clntudp_create"));
-               syslog(LOG_DEBUG, "Unable to contact %s",
-                       inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr));
-               return NULL;
+               /* We couldn't get a new CLIENT* */
+               if (!cached_client) {
+                       syslog(LOG_WARNING, "Unable to contact %s: %s",
+                               inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr),
+                               clnt_spcreateerror("clntudp_create"));
+                       return NULL;
+               }
+               /*
+                * We couldn't get updated info from portmapper, but we did
+                * still have the stale cached data.  So we might as well try
+                * to use it.
+                */
+               client = cached_client;
+               syslog(LOG_WARNING, "Unable to update contact info for %s: %s",
+                       inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr),
+                       clnt_spcreateerror("clntudp_create"));
+       } else {
+               /*
+                * We've got a new/updated CLIENT* for this host.
+                * So, destroy any previously cached CLIENT*.
+                */
+               if (cached_client)
+                       clnt_destroy(cached_client);
+
+               /*
+                * Disable the default timeout, so we can specify our own in calls
+                * to clnt_call().  (Note that the timeout is a different concept
+                * from the retry period set in clnt_udp_create() above.)
+                */
+               retry_time.tv_sec = -1;
+               retry_time.tv_usec = -1;
+               clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
+
+               if (debug_level > 3)
+                       syslog(LOG_DEBUG, "Created CLIENT* for %s",
+                           inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr));
+
+               /* make sure the new entry gets the current timestamp */
+               cache_time = time_now.tv_sec;
        }
 
-       /* Success - update the cache entry */
+update_cache_entry:
+       /* Success (of some sort) - update the cache entry */
        clnt_cache_ptr[clnt_cache_next_to_use] = client;
        memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
            host_addr->sa_len);
        clnt_cache_vers[clnt_cache_next_to_use] = vers;
-       clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
-       if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE)
+       clnt_cache_time[clnt_cache_next_to_use] = cache_time;
+       if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE)
                clnt_cache_next_to_use = 0;
 
-       /*
-        * Disable the default timeout, so we can specify our own in calls
-        * to clnt_call().  (Note that the timeout is a different concept
-        * from the retry period set in clnt_udp_create() above.)
-        */
-       retry_time.tv_sec = -1;
-       retry_time.tv_usec = -1;
-       clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
-
-       if (debug_level > 3)
-               syslog(LOG_DEBUG, "Created CLIENT* for %s",
-                   inet_ntoa(((struct sockaddr_in *)host_addr)->sin_addr));
        return client;
 }
 
@@ -273,12 +399,12 @@ get_client(host_addr, vers)
 /* transmit_result --------------------------------------------------------- */
 /*
  * Purpose:    Transmit result for nlm_xxx_msg pseudo-RPCs
- * Returns:    Nothing - we have no idea if the datagram got there
+ * Returns:    success (0) or failure (-1) at sending the datagram
  * Notes:      clnt_call() will always fail (with timeout) as we are
  *             calling it with timeout 0 as a hack to just issue a datagram
  *             without expecting a result
  */
-void
+int
 transmit_result(opcode, result, addr)
        int opcode;
        nlm_res *result;
@@ -299,17 +425,19 @@ transmit_result(opcode, result, addr)
                if (debug_level > 2)
                        syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
                            success, clnt_sperrno(success));
+               return (0);
        }
+       return (-1);
 }
 /* transmit4_result --------------------------------------------------------- */
 /*
  * Purpose:    Transmit result for nlm4_xxx_msg pseudo-RPCs
- * Returns:    Nothing - we have no idea if the datagram got there
+ * Returns:    success (0) or failure (-1) at sending the datagram
  * Notes:      clnt_call() will always fail (with timeout) as we are
  *             calling it with timeout 0 as a hack to just issue a datagram
  *             without expecting a result
  */
-void
+int
 transmit4_result(opcode, result, addr)
        int opcode;
        nlm4_res *result;
@@ -330,7 +458,9 @@ transmit4_result(opcode, result, addr)
                if (debug_level > 2)
                        syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
                            success, clnt_sperrno(success));
+               return (0);
        }
+       return (-1);
 }
 
 /*
@@ -342,7 +472,10 @@ nlmtonlm4(arg, arg4)
        struct nlm_lock *arg;
        struct nlm4_lock *arg4;
 {
-       memcpy(arg4, arg, sizeof(nlm_lock));
+       arg4->caller_name = arg->caller_name;
+       arg4->fh = arg->fh;
+       arg4->oh = arg->oh;
+       arg4->svid = arg->svid;
        arg4->l_offset = arg->l_offset;
        arg4->l_len = arg->l_len;
 }
@@ -513,8 +646,20 @@ nlm_lock_msg_1_svc(arg, rqstp)
 
        res.cookie = arg->cookie;
        res.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON);
-       transmit_result(NLM_LOCK_RES, &res,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+       if (transmit_result(NLM_LOCK_RES, &res,
+           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) {
+               /* if res.stat.stat was success/blocked, then unlock/cancel */
+               if (res.stat.stat == nlm_granted)
+                       unlock(&arg4.alock, LOCK_V4);
+               else if (res.stat.stat == nlm_blocked) {
+                       nlm4_cancargs carg;
+                       carg.cookie = arg4.cookie;
+                       carg.block = arg4.block;
+                       carg.exclusive = arg4.exclusive;
+                       carg.alock = arg4.alock;
+                       cancellock(&carg, 0);
+               }
+       }
 
        return (NULL);
 }
@@ -566,8 +711,10 @@ nlm_cancel_msg_1_svc(arg, rqstp)
 
        res.cookie = arg->cookie;
        res.stat.stat = cancellock(&arg4, 0);
-       transmit_result(NLM_CANCEL_RES, &res,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+       if (transmit_result(NLM_CANCEL_RES, &res,
+           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) {
+               /* XXX do we need to (un)do anything if this fails? */
+       }
        return (NULL);
 }
 
@@ -614,8 +761,10 @@ nlm_unlock_msg_1_svc(arg, rqstp)
        res.stat.stat = unlock(&arg4, 0);
        res.cookie = arg->cookie;
 
-       transmit_result(NLM_UNLOCK_RES, &res,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+       if (transmit_result(NLM_UNLOCK_RES, &res,
+           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) {
+               /* XXX do we need to (un)do anything if this fails? */
+       }
        return (NULL);
 }
 
@@ -697,8 +846,10 @@ nlm_granted_msg_1_svc(arg, rqstp)
 
        res.cookie = arg->cookie;
 
-       transmit_result(NLM_GRANTED_RES, &res,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+       if (transmit_result(NLM_GRANTED_RES, &res,
+           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) {
+               /* XXX do we need to (un)do anything if this fails? */
+       }
        return (NULL);
 }
 
@@ -1078,8 +1229,20 @@ nlm4_lock_msg_4_svc(arg, rqstp)
 
        res.cookie = arg->cookie;
        res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4);
-       transmit4_result(NLM4_LOCK_RES, &res,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+       if (transmit4_result(NLM4_LOCK_RES, &res,
+           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) {
+               /* if res.stat.stat was success/blocked, then unlock/cancel */
+               if (res.stat.stat == nlm4_granted)
+                       unlock(&arg->alock, LOCK_V4);
+               else if (res.stat.stat == nlm4_blocked) {
+                       nlm4_cancargs carg;
+                       carg.cookie = arg->cookie;
+                       carg.block = arg->block;
+                       carg.exclusive = arg->exclusive;
+                       carg.alock = arg->alock;
+                       cancellock(&carg, LOCK_V4);
+               }
+       }
 
        return (NULL);
 }
@@ -1119,8 +1282,10 @@ nlm4_cancel_msg_4_svc(arg, rqstp)
 
        res.cookie = arg->cookie;
        res.stat.stat = cancellock(arg, LOCK_V4);
-       transmit4_result(NLM4_CANCEL_RES, &res,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+       if (transmit4_result(NLM4_CANCEL_RES, &res,
+           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) {
+               /* XXX do we need to (un)do anything if this fails? */
+       }
        return (NULL);
 }
 
@@ -1161,8 +1326,10 @@ nlm4_unlock_msg_4_svc(arg, rqstp)
        res.stat.stat = unlock(&arg->alock, LOCK_V4);
        res.cookie = arg->cookie;
 
-       transmit4_result(NLM4_UNLOCK_RES, &res,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+       if (transmit4_result(NLM4_UNLOCK_RES, &res,
+           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) {
+               /* XXX do we need to (un)do anything if this fails? */
+       }
        return (NULL);
 }
 
@@ -1232,8 +1399,10 @@ nlm4_granted_msg_4_svc(arg, rqstp)
 
        res.cookie = arg->cookie;
 
-       transmit4_result(NLM4_GRANTED_RES, &res,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
+       if (transmit4_result(NLM4_GRANTED_RES, &res,
+           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt)) < 0) {
+               /* XXX do we need to (un)do anything if this fails? */
+       }
        return (NULL);
 }
 
index f2d9ef2668ee288e258c0bf45620609d324636ca..7bb58331f3d41c3e9e60f731ab39728ff506b3b4 100644 (file)
@@ -59,6 +59,7 @@ __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $");
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <sys/resource.h>
 
 #include <rpc/rpc.h>
 #include <rpc/pmap_clnt.h>
@@ -103,6 +104,7 @@ main(argc, argv)
        int ch;
        struct sigaction sigalarm;
        int grace_period = 30;
+       struct rlimit rlp;
        
        while ((ch = getopt(argc, argv, "d:g:wx:")) != (-1)) {
                switch (ch) {
@@ -141,7 +143,7 @@ main(argc, argv)
         * Note that it is NOT sensible to run this program from inetd - the
         * protocol assumes that it will run immediately at boot time.
         */
-       if (debug_level != 99 && daemon(0, 0)) {
+       if (debug_level != 99 && daemon(0, debug_level > 0)) {
                err(1, "cannot fork");
                /* NOTREACHED */
        }
@@ -152,8 +154,12 @@ main(argc, argv)
        signal(SIGHUP, handle_sig_cleanup);
        signal(SIGQUIT, handle_sig_cleanup);
 
-       if (claim_pid_file("/var/run/lockd.pid", 0) < 0)
-               errx(1, "cannot claim pid file");
+       openlog("rpc.lockd", debug_level == 99 ? LOG_PERROR : 0, LOG_DAEMON);
+
+       if (claim_pid_file("/var/run/lockd.pid", 0) < 0) {
+               syslog(LOG_ERR, "cannot claim pid file");
+               exit(1);
+       }
 
        if (waitkern) {
                struct timespec ts;
@@ -168,7 +174,6 @@ main(argc, argv)
                nanosleep(&ts, NULL);
        }
 
-       openlog("rpc.lockd", debug_level == 99 ? LOG_PERROR : 0, LOG_DAEMON);
        if (debug_level)
                syslog(LOG_INFO, "Starting, debug level %d", debug_level);
        else
@@ -180,24 +185,48 @@ main(argc, argv)
        (void)pmap_unset(NLM_PROG, NLM_VERS4);
 
        transp = svcudp_create(RPC_ANYSOCK);
-       if (transp == NULL)
-               errx(1, "cannot create udp service");
-       if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP))
-               errx(1, "unable to register (NLM_PROG, NLM_VERS, udp)");
-       if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP))
-               errx(1, "unable to register (NLM_PROG, NLM_VERSX, udp)");
-       if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_UDP))
-               errx(1, "unable to register (NLM_PROG, NLM_VERS4, udp)");
+       if (transp == NULL) {
+               syslog(LOG_ERR, "cannot create udp service");
+               exit(1);
+       }
+       if (!svc_register(transp, NLM_PROG, NLM_SM, nlm_prog_0, IPPROTO_UDP)) {
+               syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_SM, udp)");
+               exit(1);
+       }
+       if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP)) {
+               syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERS, udp)");
+               exit(1);
+       }
+       if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP)) {
+               syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERSX, udp)");
+               exit(1);
+       }
+       if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_UDP)) {
+               syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERS4, udp)");
+               exit(1);
+       }
         
        transp = svctcp_create(RPC_ANYSOCK, 0, 0);
-       if (transp == NULL)
-               errx(1, "cannot create tcp service");
-       if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP))
-               errx(1, "unable to register (NLM_PROG, NLM_VERS, tcp)");
-       if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP))  
-               errx(1, "unable to register (NLM_PROG, NLM_VERSX, tcp)");
-       if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_TCP))   
-               errx(1, "unable to register (NLM_PROG, NLM_VERS4, tcp)");
+       if (transp == NULL) {
+               syslog(LOG_ERR, "cannot create tcp service");
+               exit(1);
+       }
+       if (!svc_register(transp, NLM_PROG, NLM_SM, nlm_prog_0, IPPROTO_TCP)) {
+               syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_SM, tcp)");
+               exit(1);
+       }
+       if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP)) {
+               syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERS, tcp)");
+               exit(1);
+       }
+       if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP))   {
+               syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERSX, tcp)");
+               exit(1);
+       }
+       if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_TCP))    {
+               syslog(LOG_ERR, "unable to register (NLM_PROG, NLM_VERS4, tcp)");
+               exit(1);
+       }
 
        sigalarm.sa_handler = (sig_t) sigalarm_handler;
        sigemptyset(&sigalarm.sa_mask);
@@ -215,6 +244,18 @@ main(argc, argv)
 
        client_pid = client_request();
 
+       /* raise our resource limits as far as they can go */
+       if (getrlimit(RLIMIT_NOFILE, &rlp)) {
+               syslog(LOG_WARNING, "getrlimit(RLIMIT_NOFILE) failed: %s",
+                       strerror(errno));
+       } else {
+               rlp.rlim_cur = rlp.rlim_max;
+               if (setrlimit(RLIMIT_NOFILE, &rlp)) {
+                       syslog(LOG_WARNING, "setrlimit(RLIMIT_NOFILE) failed: %s",
+                               strerror(errno));
+               }
+       }
+
        my_svc_run();           /* Should never return */
        exit(1);
 }
@@ -265,7 +306,7 @@ init_nsm(void)
                ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
                    xdr_my_id, &id, xdr_sm_stat, &stat);
                if (ret) {
-                       warnx("%lu %s", SM_PROG, clnt_sperrno(ret));
+                       syslog(LOG_WARNING, "%lu %s", SM_PROG, clnt_sperrno(ret));
                        if (++attempt < 20) {
                                sleep(attempt);
                                continue;
@@ -275,7 +316,8 @@ init_nsm(void)
        } while (1);
 
        if (ret != 0) {
-               errx(1, "%lu %s", SM_PROG, clnt_sperrno(ret));
+               syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
+               exit(1);
        }
 
        nsm_state = stat.state;
index 29a77c56f636ae9d03e3da111566de00d7d8b24a..1d69479d4bd4d1f4ecebc5395c65ab49e5c30989 100644 (file)
 #define MAXOBJECTSIZE 64
 #define MAXBUFFERSIZE 1024
 
-/*
- * SM_MAXSTRLEN is usually 1024.  This means that lock requests and
- * host name monitoring entries are *MUCH* larger than they should be
- */
-
 /*
  * A set of utilities for managing file locking
  *
@@ -83,13 +78,11 @@ struct file_lock {
        struct sockaddr *addr;
        struct nlm4_holder client; /* lock holder */
        u_int64_t granted_cookie;
-       char client_name[SM_MAXSTRLEN];
        int nsm_status; /* status from the remote lock manager */
        int status; /* lock status, see below */
        int flags; /* lock flags, see lockd_lock.h */
        int blocking; /* blocking lock or not */
-       pid_t locker; /* pid of the child process trying to get the lock */
-       int fd; /* file descriptor for this lock */
+       char client_name[SM_MAXSTRLEN]; /* client_name is really variable length and must be last! */
 };
 
 LIST_HEAD(nfslocklist_head, file_lock);
@@ -102,9 +95,9 @@ struct blockedlocklist_head blockedlocklist_head = LIST_HEAD_INITIALIZER(blocked
 struct file_share {
        LIST_ENTRY(file_share) nfssharelist;
        netobj oh; /* share holder */
-       char client_name[SM_MAXSTRLEN];
        short mode;
        short access;
+       char client_name[SM_MAXSTRLEN]; /* name is really variable length and must be last! */
 };
 LIST_HEAD(nfssharelist_head, file_share);
 
@@ -129,9 +122,10 @@ struct nfssharefilelist_head nfssharefilelist_head = LIST_HEAD_INITIALIZER(nfssh
 /* struct describing a monitored host */
 struct host {
        TAILQ_ENTRY(host) hostlst;
-       char name[SM_MAXSTRLEN];
        int refcnt;
        time_t lastuse;
+       struct sockaddr addr;
+       char name[SM_MAXSTRLEN]; /* name is really variable length and must be last! */
 };
 /* list of hosts we monitor */
 TAILQ_HEAD(hostlst_head, host);
@@ -187,17 +181,17 @@ int send_granted(struct file_lock *fl, int opcode);
 void siglock(void);
 void sigunlock(void);
 void destroy_lock_host(struct host *ihp);
-void monitor_lock_host(const char *hostname);
-void unmonitor_lock_host(const char *hostname);
+static void monitor_lock_host(const char *hostname, const struct sockaddr *addr);
 
 void   copy_nlm4_lock_to_nlm4_holder(const struct nlm4_lock *src,
     const bool_t exclusive, struct nlm4_holder *dest);
 struct file_lock *     allocate_file_lock(const netobj *lockowner,
-    const netobj *filehandle);
+    const netobj *filehandle, const struct sockaddr *addr,
+    const char *caller_name);
 void   deallocate_file_lock(struct file_lock *fl);
 void   fill_file_lock(struct file_lock *fl,
-    struct sockaddr *addr, const bool_t exclusive, const int32_t svid,
-    const u_int64_t offset, const u_int64_t len, const char *caller_name,
+    const bool_t exclusive, const int32_t svid,
+    const u_int64_t offset, const u_int64_t len,
     const int state, const int status, const int flags, const int blocking);
 int    regions_overlap(const u_int64_t start1, const u_int64_t len1,
     const u_int64_t start2, const u_int64_t len2);;
@@ -397,20 +391,40 @@ copy_nlm4_lock_to_nlm4_holder(src, exclusive, dest)
 }
 
 
+size_t
+strnlen(const char *s, size_t len)
+{
+    size_t n;
+
+    for (n = 0;  s[n] != 0 && n < len; n++)
+        ;
+    return n;
+}
+
 /*
  * allocate_file_lock: Create a lock with the given parameters
  */
 
 struct file_lock *
-allocate_file_lock(const netobj *lockowner, const netobj *filehandle)
+allocate_file_lock(const netobj *lockowner, const netobj *filehandle,
+                  const struct sockaddr *addr, const char *caller_name)
 {
        struct file_lock *newfl;
+       size_t n;
+
+       /* Beware of rubbish input! */
+       n = strnlen(caller_name, SM_MAXSTRLEN);
+       if (n == SM_MAXSTRLEN) {
+               return NULL;
+       }
 
-       newfl = malloc(sizeof(struct file_lock));
+       newfl = malloc(sizeof(*newfl) - sizeof(newfl->client_name) + n + 1);
        if (newfl == NULL) {
                return NULL;
        }
-       bzero(newfl, sizeof(newfl));
+       bzero(newfl, sizeof(*newfl) - sizeof(newfl->client_name));
+       memcpy(newfl->client_name, caller_name, n);
+       newfl->client_name[n] = 0;
 
        newfl->client.oh.n_bytes = malloc(lockowner->n_len);
        if (newfl->client.oh.n_bytes == NULL) {
@@ -429,6 +443,14 @@ allocate_file_lock(const netobj *lockowner, const netobj *filehandle)
        newfl->filehandle.n_len = filehandle->n_len;
        bcopy(filehandle->n_bytes, newfl->filehandle.n_bytes, filehandle->n_len);
 
+       newfl->addr = malloc(addr->sa_len);
+       if (newfl->addr == NULL) {
+               free(newfl->client.oh.n_bytes);
+               free(newfl);
+               return NULL;
+       }
+       memcpy(newfl->addr, addr, addr->sa_len);
+
        return newfl;
 }
 
@@ -437,19 +459,15 @@ allocate_file_lock(const netobj *lockowner, const netobj *filehandle)
  */
 void
 fill_file_lock(struct file_lock *fl,
-    struct sockaddr *addr, const bool_t exclusive, const int32_t svid,
-    const u_int64_t offset, const u_int64_t len, const char *caller_name,
+    const bool_t exclusive, const int32_t svid,
+    const u_int64_t offset, const u_int64_t len,
     const int state, const int status, const int flags, const int blocking)
 {
-       fl->addr = addr;
-
        fl->client.exclusive = exclusive;
        fl->client.svid = svid;
        fl->client.l_offset = offset;
        fl->client.l_len = len;
 
-       strncpy(fl->client_name, caller_name, SM_MAXSTRLEN);
-
        fl->nsm_status = state;
        fl->status = status;
        fl->flags = flags;
@@ -462,6 +480,7 @@ fill_file_lock(struct file_lock *fl,
 void
 deallocate_file_lock(struct file_lock *fl)
 {
+       free(fl->addr);
        free(fl->client.oh.n_bytes);
        free(fl->filehandle.n_bytes);
        free(fl);
@@ -948,22 +967,21 @@ split_nfslock(exist_lock, unlock_lock, left_lock, right_lock)
            &start1, &len1, &start2, &len2);
 
        if ((spstatus & SPL_LOCK1) != 0) {
-               *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle);
+               *left_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle, exist_lock->addr, exist_lock->client_name);
                if (*left_lock == NULL) {
                        debuglog("Unable to allocate resource for split 1\n");
                        return SPL_RESERR;
                }
 
                fill_file_lock(*left_lock,
-                   exist_lock->addr,
                    exist_lock->client.exclusive, exist_lock->client.svid,
                    start1, len1,
-                   exist_lock->client_name, exist_lock->nsm_status,
+                   exist_lock->nsm_status,
                    exist_lock->status, exist_lock->flags, exist_lock->blocking);
        }
 
        if ((spstatus & SPL_LOCK2) != 0) {
-               *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle);
+               *right_lock = allocate_file_lock(&exist_lock->client.oh, &exist_lock->filehandle, exist_lock->addr, exist_lock->client_name);
                if (*right_lock == NULL) {
                        debuglog("Unable to allocate resource for split 1\n");
                        if (*left_lock != NULL) {
@@ -973,10 +991,9 @@ split_nfslock(exist_lock, unlock_lock, left_lock, right_lock)
                }
 
                fill_file_lock(*right_lock,
-                   exist_lock->addr,
                    exist_lock->client.exclusive, exist_lock->client.svid,
                    start2, len2,
-                   exist_lock->client_name, exist_lock->nsm_status,
+                   exist_lock->nsm_status,
                    exist_lock->status, exist_lock->flags, exist_lock->blocking);
        }
 
@@ -1002,7 +1019,7 @@ unlock_nfslock(fl, released_lock, left_lock, right_lock)
 
        retval = NFS_DENIED_NOLOCK;
 
-       printf("Attempting to match lock...\n");
+       debuglog("Attempting to match lock...\n");
        mfl = get_lock_matching_unlock(fl);
 
        if (mfl != NULL) {
@@ -1091,7 +1108,7 @@ lock_hwlock(struct file_lock *fl)
                return (HW_RESERR);
        }
        nmf->filehandle.n_bytes = malloc(fl->filehandle.n_len);
-       if (nmf == NULL) {
+       if (nmf->filehandle.n_bytes == NULL) {
                debuglog("hwlock resource allocation failure\n");
                free(nmf);
                return (HW_RESERR);
@@ -1102,6 +1119,7 @@ lock_hwlock(struct file_lock *fl)
        if (nmf->fd < 0) {
                debuglog("fhopen failed (from %16s): %32s\n",
                    fl->client_name, strerror(errno));
+               free(nmf->filehandle.n_bytes);
                free(nmf);
                switch (errno) {
                case ESTALE:
@@ -1128,6 +1146,7 @@ lock_hwlock(struct file_lock *fl)
                debuglog("flock failed (from %16s): %32s\n",
                    fl->client_name, strerror(errno));
                close(nmf->fd);
+               free(nmf->filehandle.n_bytes);
                free(nmf);
                switch (errno) {
                case EAGAIN:
@@ -1185,6 +1204,7 @@ unlock_hwlock(const struct file_lock *fl)
        if (imf->refcount <= 0) {
                close(imf->fd);
                LIST_REMOVE(imf, monfilelist);
+               free(imf->filehandle.n_bytes);
                free(imf);
        }
        debuglog("Exiting unlock_hwlock (HW_GRANTED)\n");
@@ -1463,7 +1483,7 @@ lock_partialfilelock(struct file_lock *fl)
                                retval = PFL_GRANTED;
                        }
                        if (fl->flags & LOCK_MON)
-                               monitor_lock_host(fl->client_name);
+                               monitor_lock_host_by_name(fl->client_name);
                        break;
                case HW_RESERR:
                        debuglog("HW RESERR\n");
@@ -1505,12 +1525,17 @@ lock_partialfilelock(struct file_lock *fl)
        if (retval == PFL_NFSDENIED || retval == PFL_HWDENIED) {
                /* Once last chance to check the lock */
                if (fl->blocking == 1) {
-                       /* Queue the lock */
-                       debuglog("BLOCKING LOCK RECEIVED\n");
-                       retval = (retval == PFL_NFSDENIED ?
-                           PFL_NFSBLOCKED : PFL_HWBLOCKED);
-                       add_blockingfilelock(fl);
-                       dump_filelock(fl);
+                       if (retval == PFL_NFSDENIED) {
+                               /* Queue the lock */
+                               debuglog("BLOCKING LOCK RECEIVED\n");
+                               retval = PFL_NFSBLOCKED;
+                               add_blockingfilelock(fl);
+                               dump_filelock(fl);
+                       } else {
+                               /* retval is okay as PFL_HWDENIED */
+                               debuglog("BLOCKING LOCK DENIED IN HARDWARE\n");
+                               dump_filelock(fl);
+                       }
                } else {
                        /* Leave retval alone, it's already correct */
                        debuglog("Lock denied.  Non-blocking failure\n");
@@ -1585,7 +1610,7 @@ unlock_partialfilelock(const struct file_lock *fl)
                                debuglog("HW duplicate lock failure for left split\n");
                        }
                        if (lfl->flags & LOCK_MON)
-                               monitor_lock_host(lfl->client_name);
+                               monitor_lock_host_by_name(lfl->client_name);
                }
 
                if (rfl != NULL) {
@@ -1595,7 +1620,7 @@ unlock_partialfilelock(const struct file_lock *fl)
                                debuglog("HW duplicate lock failure for right split\n");
                        }
                        if (rfl->flags & LOCK_MON)
-                               monitor_lock_host(rfl->client_name);
+                               monitor_lock_host_by_name(rfl->client_name);
                }
 
                switch (unlstatus) {
@@ -2003,7 +2028,9 @@ getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags)
                    nlm4_denied_grace_period : nlm_denied_grace_period;
 
        /* allocate new file_lock for this request */
-       newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->alock.fh);
+       newfl = allocate_file_lock(&lckarg->alock.oh, &lckarg->alock.fh,
+                                  (struct sockaddr *)svc_getcaller(rqstp->rq_xprt),
+                                  lckarg->alock.caller_name);
        if (newfl == NULL) {
                syslog(LOG_NOTICE, "lock allocate failed: %s", strerror(errno));
                /* failed */
@@ -2017,10 +2044,9 @@ getlock(nlm4_lockargs *lckarg, struct svc_req *rqstp, const int flags)
        }
 
        fill_file_lock(newfl,
-           (struct sockaddr *)svc_getcaller(rqstp->rq_xprt),
            lckarg->exclusive, lckarg->alock.svid, lckarg->alock.l_offset,
            lckarg->alock.l_len,
-           lckarg->alock.caller_name, lckarg->state, 0, flags, lckarg->block);
+           lckarg->state, 0, flags, lckarg->block);
        
        /*
         * newfl is now fully constructed and deallocate_file_lock
@@ -2152,7 +2178,7 @@ cancellock(nlm4_cancargs *args, const int flags __unused)
 /*
  * XXX: The following monitor/unmonitor routines 
  * have not been extensively tested (ie. no regression
- * script exists like for the locking sections
+ * script exists like for the locking sections)
  */
 
 /*
@@ -2163,24 +2189,38 @@ cancellock(nlm4_cancargs *args, const int flags __unused)
  *    enqueue it at the front of the "in use" queue.
  */
 struct host *
-get_lock_host(struct hostlst_head *hd, const char *hostname)
+get_lock_host(struct hostlst_head *hd, const char *hostname, const struct sockaddr *saddr)
 {
        struct host *ihp;
 
-       debuglog("get_lock_host %s\n", hostname);
+       if (!hostname && !saddr)
+               return (NULL);
+
+       debuglog("get_lock_host %s\n", hostname ? hostname : "addr");
        TAILQ_FOREACH(ihp, hd, hostlst) {
-               if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) {
-                       TAILQ_REMOVE(hd, ihp, hostlst);
-                       /* Host is already monitored, bump refcount */
+               if (hostname && (strncmp(hostname, ihp->name, SM_MAXSTRLEN) != 0))
+                       continue;
+               if (saddr && addrcmp(saddr, &ihp->addr))
+                       continue;
+               TAILQ_REMOVE(hd, ihp, hostlst);
+               /*
+                * Host is already monitored, so just bump the
+                * reference count.  But don't bump the reference
+                * count if we're adding additional client-side
+                * references.  Client-side monitors are done by
+                * address, are never unmonitored, and should only
+                * take one refcount.  Otherwise, repeated calls
+                * could cause the refcount to wrap.
+                */
+               if (!saddr || !ihp->addr.sa_len)
                        ++ihp->refcnt;
-                       ihp->lastuse = currsec;
-                       /* Host should only be in the monitor list once */
-                       TAILQ_INSERT_HEAD(&hostlst_head, ihp, hostlst);
-                       break;
-               }
+               ihp->lastuse = currsec;
+               /* Host should only be in the monitor list once */
+               TAILQ_INSERT_HEAD(&hostlst_head, ihp, hostlst);
+               break;
        }
        debuglog("get_lock_host %s %s\n",
-           ihp == NULL ? "did not find" : "found", hostname);
+           ihp == NULL ? "did not find" : "found", hostname ? hostname : "addr");
        return (ihp);
 }
 
@@ -2189,39 +2229,89 @@ get_lock_host(struct hostlst_head *hd, const char *hostname)
  * inform statd
  */
 void
-monitor_lock_host(const char *hostname)
+monitor_lock_host_by_name(const char *hostname)
 {
-       struct host *ihp, *nhp;
-       struct mon smon;
-       struct sm_stat_res sres;
-       int rpcret, statflag;
-
-       rpcret = 0;
-       statflag = 0;
+       struct host *ihp;
 
        debuglog("monitor_lock_host: %s\n", hostname);
-       ihp = get_lock_host(&hostlst_head, hostname);
+       ihp = get_lock_host(&hostlst_head, hostname, NULL);
        if (ihp == NULL)
-               ihp = get_lock_host(&hostlst_unref, hostname);
+               ihp = get_lock_host(&hostlst_unref, hostname, NULL);
        if (ihp != NULL) {
                debuglog("Monitor_lock_host: %s (cached)\n", hostname);
                return;
        }
 
-       debuglog("Monitor_lock_host: %s (not found, creating)\n", hostname);
-       /* Host is not yet monitored, add it */
-       nhp = malloc(sizeof(struct host));
+       monitor_lock_host(hostname, NULL);
+}
+
+void
+monitor_lock_host_by_addr(const struct sockaddr *saddr)
+{
+       struct host *ihp;
+       struct hostent *hp;
+       char hostaddr[SM_MAXSTRLEN];
+       struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
 
+       if (getnameinfo(saddr, saddr->sa_len, hostaddr, sizeof(hostaddr),
+                       NULL, 0, NI_NUMERICHOST)) {
+               debuglog("monitor_lock_host: bad address\n");
+               return;
+       }
+       debuglog("monitor_lock_host: %s\n", hostaddr);
+       ihp = get_lock_host(&hostlst_head, NULL, saddr);
+       if (ihp == NULL)
+               ihp = get_lock_host(&hostlst_unref, NULL, saddr);
+       if (ihp != NULL) {
+               debuglog("Monitor_lock_host: %s (cached)\n", ihp->name);
+               return;
+       }
+
+       hp = gethostbyaddr((char*)&sin->sin_addr, sizeof(sin->sin_addr), AF_INET);
+       if (hp) {
+               monitor_lock_host(hp->h_name, saddr);
+       } else {
+               // herror(hostaddr);
+               monitor_lock_host(hostaddr, saddr);
+       }
+}
+
+static void
+monitor_lock_host(const char *hostname, const struct sockaddr *saddr)
+{
+       struct host *nhp;
+       struct mon smon;
+       struct sm_stat_res sres;
+       int rpcret, statflag;
+       size_t n;
+
+       rpcret = 0;
+       statflag = 0;
+
+       /* Host is not yet monitored, add it */
+       debuglog("Monitor_lock_host: %s (creating)\n", hostname);
+       n = strnlen(hostname, SM_MAXSTRLEN);
+       if (n == SM_MAXSTRLEN) {
+               debuglog("monitor_lock_host: hostname too long\n");
+               return;
+       }
+       nhp = malloc(sizeof(*nhp) - sizeof(nhp->name) + n + 1);
        if (nhp == NULL) {
                debuglog("Unable to allocate entry for statd mon\n");
                return;
        }
 
        /* Allocated new host entry, now fill the fields */
-       strncpy(nhp->name, hostname, SM_MAXSTRLEN);
+       memcpy(nhp->name, hostname, n);
+       nhp->name[n] = 0;
        nhp->refcnt = 1;
        nhp->lastuse = currsec;
-       debuglog("Locally Monitoring host %16s\n",hostname);
+       if (saddr) {
+               bcopy(saddr, &nhp->addr, saddr->sa_len);
+       } else {
+               nhp->addr.sa_len = 0;
+       }
+       debuglog("Locally Monitoring host '%s'\n", hostname);
 
        debuglog("Attempting to tell statd\n");
 
@@ -2267,7 +2357,7 @@ unmonitor_lock_host(const char *hostname)
 
        TAILQ_FOREACH(ihp, &hostlst_head, hostlst) {
                if (strncmp(hostname, ihp->name, SM_MAXSTRLEN) == 0) {
-                       /* Host is monitored, bump refcount */
+                       /* Host is unmonitored, drop refcount */
                        --ihp->refcnt;
                        /* Host should only be in the monitor list once */
                        break;
@@ -2514,6 +2604,7 @@ getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags)
 {
        struct sharefile *shrfile;
        struct file_share *sh;
+       size_t n;
 
        debuglog("Entering getshare...\n");
 
@@ -2592,7 +2683,13 @@ getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags)
        }
 
        /* create/init new share */
-       sh = malloc(sizeof(struct file_share));
+       n = strnlen(shrarg->share.caller_name, SM_MAXSTRLEN);
+       if (n < SM_MAXSTRLEN) {
+               sh = malloc(sizeof(*sh) - sizeof(sh->client_name) + n + 1);
+       } else {
+               debuglog("getshare failed: hostname too long\n");
+               sh = NULL;
+       }
        if (!sh) {
                debuglog("getshare failed: can't allocate share\n");
                if (!shrfile->refcount) {
@@ -2603,6 +2700,7 @@ getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags)
                }
                return (flags & LOCK_V4) ? nlm4_failed : nlm_denied;
        }
+       bzero(sh, sizeof(*sh) - sizeof(sh->client_name));
        sh->oh.n_len = shrarg->share.oh.n_len;
        sh->oh.n_bytes = malloc(sh->oh.n_len);
        if (!sh->oh.n_bytes) {
@@ -2616,7 +2714,8 @@ getshare(nlm_shareargs *shrarg, struct svc_req *rqstp, const int flags)
                }
                return (flags & LOCK_V4) ? nlm4_failed : nlm_denied;
        }
-       strncpy(sh->client_name, shrarg->share.caller_name, SM_MAXSTRLEN);
+       memcpy(sh->client_name, shrarg->share.caller_name, n);
+       sh->client_name[n] = 0;
        sh->mode = shrarg->share.mode;
        sh->access = shrarg->share.access;
 
index 4d93c7dec1f65f6be32b4605f231b915ca2a7ead..ca1aa376a7fcfc423953f17f75365316c0a5dad9 100644 (file)
@@ -17,6 +17,10 @@ void granted_failed(nlm4_res *arg);
 
 void notify(const char *hostname, const int state);
 
+void monitor_lock_host_by_name(const char *hostname);
+void monitor_lock_host_by_addr(const struct sockaddr *addr);
+void unmonitor_lock_host(const char *hostname);
+
 /* flags for testlock, getlock & unlock */
 #define LOCK_ASYNC     0x01 /* async version (getlock only) */
 #define LOCK_V4        0x02 /* v4 version */
@@ -27,9 +31,10 @@ void notify(const char *hostname, const int state);
 #define LOCK_ANSWER_LOCK_EXCL  0x0004  /* lock is exclusive */
 
 /* callbacks from lock_proc.c */
-void   transmit_result(int, nlm_res *, struct sockaddr *);
-void   transmit4_result(int, nlm4_res *, struct sockaddr *);
+int    transmit_result(int, nlm_res *, struct sockaddr *);
+int    transmit4_result(int, nlm4_res *, struct sockaddr *);
 CLIENT  *get_client(struct sockaddr *, rpcvers_t);
+int    addrcmp(const struct sockaddr *, const struct sockaddr *);
 
 extern time_t currsec;
 
index 74aed609f3b48b0f1cb43f77340324b0d9964968..c564094dfd7d46986dd880d7484fc866028adac2 100644 (file)
@@ -381,9 +381,33 @@ void *sm_notify_1_svc(stat_chge *arg, struct svc_req *req __unused)
   hp = find_host(arg->mon_name, FALSE);
   if (!hp)
   {
-    /* Never heard of this host - why is it notifying us?              */
-    syslog(LOG_ERR, "Unsolicited notification from host %s", arg->mon_name);
-    return (&dummy);
+    /*
+     * Hmmm... We've never heard of this host.
+     * It's possible the host just didn't give us the right hostname.
+     * Let's try the IP address the request came from and any hostnames it has.
+     */
+    struct sockaddr_in *claddr;
+    if ((claddr = svc_getcaller(req->rq_xprt))) {
+      struct hostent *he;
+      he = gethostbyaddr((char*)&claddr->sin_addr, sizeof(claddr->sin_addr), AF_INET);
+      if (he) {
+        char **np = he->h_aliases;
+        hp = find_host(he->h_name, FALSE);
+        while (!hp && *np) {
+          hp = find_host(*np, FALSE);
+          if (!hp)
+            np++;
+        }
+      }
+      if (hp)
+        syslog(LOG_DEBUG, "Notification from host %s found as %s",
+          arg->mon_name, hp->hostname);
+    }
+    if (!hp) {
+      /* Never heard of this host - why is it notifying us?            */
+      syslog(LOG_DEBUG, "Unsolicited notification from host %s", arg->mon_name);
+      return (&dummy);
+    }
   }
   lp = hp->monList;
   if (!lp) return (&dummy);    /* We know this host, but have no       */
@@ -398,7 +422,7 @@ void *sm_notify_1_svc(stat_chge *arg, struct svc_req *req __unused)
 
   while (lp)
   {
-    tx_arg.mon_name = arg->mon_name;
+    tx_arg.mon_name = hp->hostname;
     tx_arg.state = arg->state;
     memcpy(tx_arg.priv, lp->notifyData, sizeof(tx_arg.priv));
     cli = clnt_create(lp->notifyHost, lp->notifyProg, lp->notifyVers, "udp");