Home | History | Annotate | Line # | Download | only in rpc.lockd
      1  1.10      tron /*	$NetBSD: lock_proc.c,v 1.10 2012/06/18 20:30:32 tron Exp $	*/
      2   1.1    scottr 
      3   1.1    scottr /*
      4   1.1    scottr  * Copyright (c) 1995
      5   1.1    scottr  *	A.R. Gordon (andrew.gordon (at) net-tel.co.uk).  All rights reserved.
      6   1.1    scottr  *
      7   1.1    scottr  * Redistribution and use in source and binary forms, with or without
      8   1.1    scottr  * modification, are permitted provided that the following conditions
      9   1.1    scottr  * are met:
     10   1.1    scottr  * 1. Redistributions of source code must retain the above copyright
     11   1.1    scottr  *    notice, this list of conditions and the following disclaimer.
     12   1.1    scottr  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1    scottr  *    notice, this list of conditions and the following disclaimer in the
     14   1.1    scottr  *    documentation and/or other materials provided with the distribution.
     15   1.1    scottr  * 3. All advertising materials mentioning features or use of this software
     16   1.1    scottr  *    must display the following acknowledgement:
     17   1.1    scottr  *	This product includes software developed for the FreeBSD project
     18   1.1    scottr  * 4. Neither the name of the author nor the names of any co-contributors
     19   1.1    scottr  *    may be used to endorse or promote products derived from this software
     20   1.1    scottr  *    without specific prior written permission.
     21   1.1    scottr  *
     22   1.1    scottr  * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
     23   1.1    scottr  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24   1.1    scottr  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25   1.1    scottr  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     26   1.1    scottr  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27   1.1    scottr  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28   1.1    scottr  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29   1.1    scottr  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30   1.1    scottr  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31   1.1    scottr  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32   1.1    scottr  * SUCH DAMAGE.
     33   1.1    scottr  *
     34   1.1    scottr  */
     35   1.1    scottr 
     36   1.2     lukem #include <sys/cdefs.h>
     37   1.2     lukem #ifndef lint
     38  1.10      tron __RCSID("$NetBSD: lock_proc.c,v 1.10 2012/06/18 20:30:32 tron Exp $");
     39   1.2     lukem #endif
     40   1.2     lukem 
     41   1.1    scottr #include <sys/param.h>
     42   1.1    scottr #include <sys/socket.h>
     43   1.1    scottr 
     44   1.1    scottr #include <netinet/in.h>
     45   1.1    scottr #include <arpa/inet.h>
     46   1.1    scottr 
     47   1.2     lukem #include <netdb.h>
     48   1.2     lukem #include <stdio.h>
     49   1.2     lukem #include <string.h>
     50   1.2     lukem #include <syslog.h>
     51   1.5      fvdl #include <netconfig.h>
     52   1.2     lukem 
     53   1.1    scottr #include <rpc/rpc.h>
     54   1.1    scottr #include <rpcsvc/sm_inter.h>
     55   1.1    scottr 
     56   1.1    scottr #include "lockd.h"
     57   1.6   thorpej #include <rpcsvc/nlm_prot.h>
     58   1.4    bouyer #include "lockd_lock.h"
     59   1.1    scottr 
     60   1.1    scottr 
     61   1.1    scottr #define	CLIENT_CACHE_SIZE	64	/* No. of client sockets cached */
     62   1.1    scottr #define	CLIENT_CACHE_LIFETIME	120	/* In seconds */
     63   1.1    scottr 
     64   1.9  christos static void	log_from_addr(const char *, struct svc_req *);
     65   1.9  christos static int	addrcmp(const struct sockaddr *, const struct sockaddr *);
     66   1.9  christos static void	nlmtonlm4(struct nlm_lock *, struct nlm4_lock *);
     67   1.2     lukem 
     68   1.1    scottr /* log_from_addr ----------------------------------------------------------- */
     69   1.1    scottr /*
     70   1.1    scottr  * Purpose:	Log name of function called and source address
     71   1.1    scottr  * Returns:	Nothing
     72   1.1    scottr  * Notes:	Extracts the source address from the transport handle
     73   1.1    scottr  *		passed in as part of the called procedure specification
     74   1.1    scottr  */
     75   1.4    bouyer static void
     76   1.9  christos log_from_addr(const char *fun_name, struct svc_req *req)
     77   1.1    scottr {
     78   1.5      fvdl 	struct sockaddr *addr;
     79   1.5      fvdl 	char hostname_buf[NI_MAXHOST];
     80   1.5      fvdl 
     81   1.5      fvdl 	addr = svc_getrpccaller(req->rq_xprt)->buf;
     82   1.9  christos 	if (getnameinfo(addr, (socklen_t)addr->sa_len, hostname_buf,
     83   1.9  christos 	    sizeof(hostname_buf), NULL, 0, 0) != 0)
     84   1.5      fvdl 		return;
     85   1.1    scottr 
     86   1.1    scottr 	syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
     87   1.1    scottr }
     88   1.1    scottr 
     89   1.1    scottr /* get_client -------------------------------------------------------------- */
     90   1.1    scottr /*
     91   1.1    scottr  * Purpose:	Get a CLIENT* for making RPC calls to lockd on given host
     92   1.1    scottr  * Returns:	CLIENT* pointer, from clnt_udp_create, or NULL if error
     93   1.1    scottr  * Notes:	Creating a CLIENT* is quite expensive, involving a
     94   1.1    scottr  *		conversation with the remote portmapper to get the
     95   1.1    scottr  *		port number.  Since a given client is quite likely
     96   1.1    scottr  *		to make several locking requests in succession, it is
     97   1.1    scottr  *		desirable to cache the created CLIENT*.
     98   1.1    scottr  *
     99   1.1    scottr  *		Since we are using UDP rather than TCP, there is no cost
    100   1.1    scottr  *		to the remote system in keeping these cached indefinitely.
    101   1.1    scottr  *		Unfortunately there is a snag: if the remote system
    102   1.1    scottr  *		reboots, the cached portmapper results will be invalid,
    103   1.1    scottr  *		and we will never detect this since all of the xxx_msg()
    104   1.1    scottr  *		calls return no result - we just fire off a udp packet
    105   1.1    scottr  *		and hope for the best.
    106   1.1    scottr  *
    107   1.1    scottr  *		We solve this by discarding cached values after two
    108   1.1    scottr  *		minutes, regardless of whether they have been used
    109   1.1    scottr  *		in the meanwhile (since a bad one might have been used
    110   1.1    scottr  *		plenty of times, as the host keeps retrying the request
    111   1.1    scottr  *		and we keep sending the reply back to the wrong port).
    112   1.1    scottr  *
    113   1.1    scottr  *		Given that the entries will always expire in the order
    114   1.1    scottr  *		that they were created, there is no point in a LRU
    115   1.1    scottr  *		algorithm for when the cache gets full - entries are
    116   1.1    scottr  *		always re-used in sequence.
    117   1.1    scottr  */
    118   1.1    scottr static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
    119   1.1    scottr static long clnt_cache_time[CLIENT_CACHE_SIZE];	/* time entry created */
    120   1.5      fvdl static struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE];
    121   1.1    scottr static int clnt_cache_next_to_use = 0;
    122   1.1    scottr 
    123   1.5      fvdl static int
    124   1.9  christos addrcmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
    125   1.5      fvdl {
    126   1.9  christos 	size_t len;
    127   1.9  christos 	const void *p1, *p2;
    128   1.5      fvdl 
    129   1.5      fvdl 	if (sa1->sa_family != sa2->sa_family)
    130   1.5      fvdl 		return -1;
    131   1.5      fvdl 
    132   1.5      fvdl 	switch (sa1->sa_family) {
    133   1.5      fvdl 	case AF_INET:
    134   1.9  christos 		p1 = &((const struct sockaddr_in *)(const void *)sa1)->sin_addr;
    135   1.9  christos 		p2 = &((const struct sockaddr_in *)(const void *)sa2)->sin_addr;
    136   1.5      fvdl 		len = 4;
    137   1.5      fvdl 		break;
    138   1.5      fvdl 	case AF_INET6:
    139   1.9  christos 		p1 = &((const struct sockaddr_in6 *)(const void *)sa1)->sin6_addr;
    140   1.9  christos 		p2 = &((const struct sockaddr_in6 *)(const void *)sa2)->sin6_addr;
    141   1.5      fvdl 		len = 16;
    142   1.5      fvdl 		break;
    143   1.5      fvdl 	default:
    144   1.5      fvdl 		return -1;
    145   1.5      fvdl 	}
    146   1.5      fvdl 
    147   1.5      fvdl 	return memcmp(p1, p2, len);
    148   1.5      fvdl }
    149   1.5      fvdl 
    150   1.4    bouyer CLIENT *
    151   1.9  christos get_client(struct sockaddr *host_addr, rpcvers_t vers)
    152   1.1    scottr {
    153   1.1    scottr 	CLIENT *client;
    154   1.1    scottr 	struct timeval retry_time, time_now;
    155   1.5      fvdl 	int i;
    156   1.9  christos 	const char *netid;
    157   1.5      fvdl 	struct netconfig *nconf;
    158   1.5      fvdl 	char host[NI_MAXHOST];
    159  1.10      tron 	int error;
    160   1.1    scottr 
    161   1.9  christos 	(void)gettimeofday(&time_now, NULL);
    162   1.1    scottr 
    163   1.1    scottr 	/*
    164   1.1    scottr 	 * Search for the given client in the cache, zapping any expired
    165   1.1    scottr 	 * entries that we happen to notice in passing.
    166   1.1    scottr 	 */
    167   1.1    scottr 	for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
    168   1.1    scottr 		client = clnt_cache_ptr[i];
    169   1.1    scottr 		if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
    170   1.1    scottr 		    < time_now.tv_sec)) {
    171   1.1    scottr 			/* Cache entry has expired. */
    172   1.1    scottr 			if (debug_level > 3)
    173   1.1    scottr 				syslog(LOG_DEBUG, "Expired CLIENT* in cache");
    174   1.1    scottr 			clnt_cache_time[i] = 0L;
    175   1.1    scottr 			clnt_destroy(client);
    176   1.1    scottr 			clnt_cache_ptr[i] = NULL;
    177   1.1    scottr 			client = NULL;
    178   1.1    scottr 		}
    179   1.9  christos 		if (client && !addrcmp((const struct sockaddr *)(const void *)
    180   1.9  christos 		    &clnt_cache_addr[i], host_addr)) {
    181   1.1    scottr 			/* Found it! */
    182   1.1    scottr 			if (debug_level > 3)
    183   1.1    scottr 				syslog(LOG_DEBUG, "Found CLIENT* in cache");
    184   1.9  christos 			return client;
    185   1.1    scottr 		}
    186   1.1    scottr 	}
    187   1.1    scottr 
    188   1.1    scottr 	/* Not found in cache.  Free the next entry if it is in use. */
    189   1.1    scottr 	if (clnt_cache_ptr[clnt_cache_next_to_use]) {
    190   1.1    scottr 		clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
    191   1.1    scottr 		clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
    192   1.1    scottr 	}
    193   1.1    scottr 
    194   1.5      fvdl 	/*
    195   1.5      fvdl 	 * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
    196   1.5      fvdl 	 * to avoid DNS lookups.
    197   1.5      fvdl 	 */
    198  1.10      tron 	error = getnameinfo(host_addr, (socklen_t)host_addr->sa_len, host,
    199  1.10      tron 	    sizeof(host), NULL, 0, NI_NUMERICHOST);
    200  1.10      tron 	if (error != 0) {
    201  1.10      tron 		syslog(LOG_ERR, "unable to get name string for caller: %s",
    202  1.10      tron 		    gai_strerror(error));
    203   1.5      fvdl 		return NULL;
    204   1.5      fvdl 	}
    205   1.5      fvdl 
    206   1.4    bouyer #if 1
    207   1.5      fvdl 	if (host_addr->sa_family == AF_INET6)
    208   1.5      fvdl 		netid = "udp6";
    209   1.5      fvdl 	else
    210   1.5      fvdl 		netid = "udp";
    211   1.4    bouyer #else
    212   1.5      fvdl 	if (host_addr->sa_family == AF_INET6)
    213   1.5      fvdl 		netid = "tcp6";
    214   1.5      fvdl 	else
    215   1.5      fvdl 		netid = "tcp";
    216   1.4    bouyer #endif
    217   1.5      fvdl 	nconf = getnetconfigent(netid);
    218   1.5      fvdl 	if (nconf == NULL) {
    219   1.5      fvdl 		syslog(LOG_ERR, "could not get netconfig info for '%s': "
    220   1.5      fvdl 				"no /etc/netconfig file?", netid);
    221   1.5      fvdl 		return NULL;
    222   1.5      fvdl 	}
    223   1.5      fvdl 
    224   1.5      fvdl 	client = clnt_tp_create(host, NLM_PROG, vers, nconf);
    225   1.5      fvdl 	freenetconfigent(nconf);
    226   1.5      fvdl 
    227   1.1    scottr 	if (!client) {
    228   1.7        is 		syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create"));
    229   1.5      fvdl 		syslog(LOG_ERR, "Unable to return result to %s", host);
    230   1.1    scottr 		return NULL;
    231   1.1    scottr 	}
    232   1.1    scottr 
    233   1.1    scottr 	/* Success - update the cache entry */
    234   1.1    scottr 	clnt_cache_ptr[clnt_cache_next_to_use] = client;
    235   1.9  christos 	(void)memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
    236   1.9  christos 	    (size_t)host_addr->sa_len);
    237   1.1    scottr 	clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
    238   1.8      tron 	if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE)
    239   1.1    scottr 		clnt_cache_next_to_use = 0;
    240   1.1    scottr 
    241   1.1    scottr 	/*
    242   1.1    scottr 	 * Disable the default timeout, so we can specify our own in calls
    243   1.1    scottr 	 * to clnt_call().  (Note that the timeout is a different concept
    244   1.1    scottr 	 * from the retry period set in clnt_udp_create() above.)
    245   1.1    scottr 	 */
    246   1.1    scottr 	retry_time.tv_sec = -1;
    247   1.1    scottr 	retry_time.tv_usec = -1;
    248   1.9  christos 	clnt_control(client, CLSET_TIMEOUT, (char *)(void *)&retry_time);
    249   1.1    scottr 
    250   1.1    scottr 	if (debug_level > 3)
    251   1.5      fvdl 		syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
    252   1.1    scottr 	return client;
    253   1.1    scottr }
    254   1.1    scottr 
    255   1.1    scottr 
    256   1.1    scottr /* transmit_result --------------------------------------------------------- */
    257   1.1    scottr /*
    258   1.1    scottr  * Purpose:	Transmit result for nlm_xxx_msg pseudo-RPCs
    259   1.1    scottr  * Returns:	Nothing - we have no idea if the datagram got there
    260   1.1    scottr  * Notes:	clnt_call() will always fail (with timeout) as we are
    261   1.1    scottr  *		calling it with timeout 0 as a hack to just issue a datagram
    262   1.1    scottr  *		without expecting a result
    263   1.1    scottr  */
    264   1.4    bouyer void
    265   1.9  christos transmit_result(int opcode, nlm_res *result, struct sockaddr *addr)
    266   1.1    scottr {
    267   1.1    scottr 	static char dummy;
    268   1.1    scottr 	CLIENT *cli;
    269   1.1    scottr 	struct timeval timeo;
    270   1.1    scottr 	int success;
    271   1.1    scottr 
    272   1.5      fvdl 	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
    273   1.1    scottr 		timeo.tv_sec = 0; /* No timeout - not expecting response */
    274   1.1    scottr 		timeo.tv_usec = 0;
    275   1.1    scottr 
    276   1.9  christos 		success = clnt_call(cli, (rpcproc_t)opcode, xdr_nlm_res,
    277   1.9  christos 		    result, xdr_void, &dummy, timeo);
    278   1.1    scottr 
    279   1.1    scottr 		if (debug_level > 2)
    280   1.4    bouyer 			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
    281   1.4    bouyer 			    success, clnt_sperrno(success));
    282   1.1    scottr 	}
    283   1.1    scottr }
    284   1.3    bouyer /* transmit4_result --------------------------------------------------------- */
    285   1.3    bouyer /*
    286   1.3    bouyer  * Purpose:	Transmit result for nlm4_xxx_msg pseudo-RPCs
    287   1.3    bouyer  * Returns:	Nothing - we have no idea if the datagram got there
    288   1.3    bouyer  * Notes:	clnt_call() will always fail (with timeout) as we are
    289   1.3    bouyer  *		calling it with timeout 0 as a hack to just issue a datagram
    290   1.3    bouyer  *		without expecting a result
    291   1.3    bouyer  */
    292   1.4    bouyer void
    293   1.9  christos transmit4_result(int opcode, nlm4_res *result, struct sockaddr *addr)
    294   1.3    bouyer {
    295   1.3    bouyer 	static char dummy;
    296   1.3    bouyer 	CLIENT *cli;
    297   1.3    bouyer 	struct timeval timeo;
    298   1.3    bouyer 	int success;
    299   1.3    bouyer 
    300   1.5      fvdl 	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
    301   1.3    bouyer 		timeo.tv_sec = 0; /* No timeout - not expecting response */
    302   1.3    bouyer 		timeo.tv_usec = 0;
    303   1.3    bouyer 
    304   1.9  christos 		success = clnt_call(cli, (rpcproc_t)opcode, xdr_nlm4_res,
    305   1.9  christos 		    result, xdr_void, &dummy, timeo);
    306   1.3    bouyer 
    307   1.3    bouyer 		if (debug_level > 2)
    308   1.4    bouyer 			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
    309   1.4    bouyer 			    success, clnt_sperrno(success));
    310   1.3    bouyer 	}
    311   1.3    bouyer }
    312   1.4    bouyer 
    313   1.4    bouyer /*
    314   1.4    bouyer  * converts a struct nlm_lock to struct nlm4_lock
    315   1.4    bouyer  */
    316   1.4    bouyer static void
    317   1.9  christos nlmtonlm4(struct nlm_lock *arg, struct nlm4_lock *arg4)
    318   1.4    bouyer {
    319   1.9  christos 	(void)memcpy(arg4, arg, sizeof(nlm_lock));
    320   1.4    bouyer 	arg4->l_offset = arg->l_offset;
    321   1.4    bouyer 	arg4->l_len = arg->l_len;
    322   1.4    bouyer }
    323   1.9  christos 
    324   1.1    scottr /* ------------------------------------------------------------------------- */
    325   1.1    scottr /*
    326   1.1    scottr  * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
    327   1.1    scottr  * involved to ensure reclaim of locks after a crash of the "stateless"
    328   1.1    scottr  * server.
    329   1.1    scottr  *
    330   1.1    scottr  * These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
    331   1.1    scottr  * The first are standard RPCs with argument and result.
    332   1.1    scottr  * The nlm_xxx_msg() calls implement exactly the same functions, but
    333   1.1    scottr  * use two pseudo-RPCs (one in each direction).  These calls are NOT
    334   1.1    scottr  * standard use of the RPC protocol in that they do not return a result
    335   1.1    scottr  * at all (NB. this is quite different from returning a void result).
    336   1.1    scottr  * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
    337   1.1    scottr  * datagrams, requiring higher-level code to perform retries.
    338   1.1    scottr  *
    339   1.1    scottr  * Despite the disadvantages of the nlm_xxx_msg() approach (some of which
    340   1.1    scottr  * are documented in the comments to get_client() above), this is the
    341   1.1    scottr  * interface used by all current commercial NFS implementations
    342   1.1    scottr  * [Solaris, SCO, AIX etc.].  This is presumed to be because these allow
    343   1.1    scottr  * implementations to continue using the standard RPC libraries, while
    344   1.1    scottr  * avoiding the block-until-result nature of the library interface.
    345   1.1    scottr  *
    346   1.1    scottr  * No client implementations have been identified so far that make use
    347   1.1    scottr  * of the true RPC version (early SunOS releases would be a likely candidate
    348   1.1    scottr  * for testing).
    349   1.1    scottr  */
    350   1.1    scottr 
    351   1.1    scottr /* nlm_test ---------------------------------------------------------------- */
    352   1.1    scottr /*
    353   1.1    scottr  * Purpose:	Test whether a specified lock would be granted if requested
    354   1.1    scottr  * Returns:	nlm_granted (or error code)
    355   1.1    scottr  * Notes:
    356   1.1    scottr  */
    357   1.1    scottr nlm_testres *
    358   1.9  christos nlm_test_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
    359   1.1    scottr {
    360   1.9  christos 	static nlm_testres result;
    361   1.4    bouyer 	struct nlm4_lock arg4;
    362   1.4    bouyer 	struct nlm4_holder *holder;
    363   1.4    bouyer 	nlmtonlm4(&arg->alock, &arg4);
    364   1.1    scottr 
    365   1.1    scottr 	if (debug_level)
    366   1.1    scottr 		log_from_addr("nlm_test", rqstp);
    367   1.1    scottr 
    368   1.4    bouyer 	holder = testlock(&arg4, 0);
    369   1.1    scottr 	/*
    370   1.1    scottr 	 * Copy the cookie from the argument into the result.  Note that this
    371   1.1    scottr 	 * is slightly hazardous, as the structure contains a pointer to a
    372   1.1    scottr 	 * malloc()ed buffer that will get freed by the caller.  However, the
    373   1.1    scottr 	 * main function transmits the result before freeing the argument
    374   1.1    scottr 	 * so it is in fact safe.
    375   1.1    scottr 	 */
    376   1.9  christos 	result.cookie = arg->cookie;
    377   1.4    bouyer 	if (holder == NULL) {
    378   1.9  christos 		result.stat.stat = nlm_granted;
    379   1.4    bouyer 	} else {
    380   1.9  christos 		result.stat.stat = nlm_denied;
    381   1.9  christos 		(void)memcpy(&result.stat.nlm_testrply_u.holder, holder,
    382   1.4    bouyer 		    sizeof(struct nlm_holder));
    383   1.9  christos 		result.stat.nlm_testrply_u.holder.l_offset =
    384   1.9  christos 		    (unsigned int)holder->l_offset;
    385   1.9  christos 		result.stat.nlm_testrply_u.holder.l_len =
    386   1.9  christos 		    (unsigned int)holder->l_len;
    387   1.4    bouyer 	}
    388   1.9  christos 	return &result;
    389   1.1    scottr }
    390   1.1    scottr 
    391   1.1    scottr void *
    392   1.9  christos nlm_test_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
    393   1.1    scottr {
    394   1.9  christos 	nlm_testres result;
    395   1.1    scottr 	static char dummy;
    396   1.5      fvdl 	struct sockaddr *addr;
    397   1.1    scottr 	CLIENT *cli;
    398   1.1    scottr 	int success;
    399   1.1    scottr 	struct timeval timeo;
    400   1.4    bouyer 	struct nlm4_lock arg4;
    401   1.4    bouyer 	struct nlm4_holder *holder;
    402   1.4    bouyer 
    403   1.4    bouyer 	nlmtonlm4(&arg->alock, &arg4);
    404   1.1    scottr 
    405   1.1    scottr 	if (debug_level)
    406   1.1    scottr 		log_from_addr("nlm_test_msg", rqstp);
    407   1.1    scottr 
    408   1.4    bouyer 	holder = testlock(&arg4, 0);
    409   1.4    bouyer 
    410   1.9  christos 	result.cookie = arg->cookie;
    411   1.4    bouyer 	if (holder == NULL) {
    412   1.9  christos 		result.stat.stat = nlm_granted;
    413   1.4    bouyer 	} else {
    414   1.9  christos 		result.stat.stat = nlm_denied;
    415   1.9  christos 		(void)memcpy(&result.stat.nlm_testrply_u.holder, holder,
    416   1.4    bouyer 		    sizeof(struct nlm_holder));
    417   1.9  christos 		result.stat.nlm_testrply_u.holder.l_offset =
    418   1.9  christos 		    (unsigned int)holder->l_offset;
    419   1.9  christos 		result.stat.nlm_testrply_u.holder.l_len =
    420   1.9  christos 		    (unsigned int)holder->l_len;
    421   1.4    bouyer 	}
    422   1.1    scottr 
    423   1.1    scottr 	/*
    424   1.1    scottr 	 * nlm_test has different result type to the other operations, so
    425   1.1    scottr 	 * can't use transmit_result() in this case
    426   1.1    scottr 	 */
    427   1.5      fvdl 	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
    428   1.4    bouyer 	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
    429   1.1    scottr 		timeo.tv_sec = 0; /* No timeout - not expecting response */
    430   1.1    scottr 		timeo.tv_usec = 0;
    431   1.1    scottr 
    432   1.1    scottr 		success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres,
    433   1.9  christos 		    &result, xdr_void, &dummy, timeo);
    434   1.1    scottr 
    435   1.1    scottr 		if (debug_level > 2)
    436   1.4    bouyer 			syslog(LOG_DEBUG, "clnt_call returns %d", success);
    437   1.1    scottr 	}
    438   1.9  christos 	return NULL;
    439   1.1    scottr }
    440   1.1    scottr 
    441   1.1    scottr /* nlm_lock ---------------------------------------------------------------- */
    442   1.1    scottr /*
    443   1.1    scottr  * Purposes:	Establish a lock
    444   1.1    scottr  * Returns:	granted, denied or blocked
    445   1.1    scottr  * Notes:	*** grace period support missing
    446   1.1    scottr  */
    447   1.1    scottr nlm_res *
    448   1.9  christos nlm_lock_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
    449   1.1    scottr {
    450   1.9  christos 	static nlm_res result;
    451   1.4    bouyer 	struct nlm4_lockargs arg4;
    452   1.4    bouyer 	nlmtonlm4(&arg->alock, &arg4.alock);
    453   1.4    bouyer 	arg4.cookie = arg->cookie;
    454   1.4    bouyer 	arg4.block = arg->block;
    455   1.4    bouyer 	arg4.exclusive = arg->exclusive;
    456   1.4    bouyer 	arg4.reclaim = arg->reclaim;
    457   1.4    bouyer 	arg4.state = arg->state;
    458   1.1    scottr 
    459   1.1    scottr 	if (debug_level)
    460   1.1    scottr 		log_from_addr("nlm_lock", rqstp);
    461   1.1    scottr 
    462   1.1    scottr 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    463   1.9  christos 	result.cookie = arg->cookie;
    464   1.1    scottr 
    465   1.9  christos 	result.stat.stat = getlock(&arg4, rqstp, LOCK_MON);
    466   1.9  christos 	return &result;
    467   1.1    scottr }
    468   1.1    scottr 
    469   1.1    scottr void *
    470   1.9  christos nlm_lock_msg_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
    471   1.1    scottr {
    472   1.9  christos 	static nlm_res result;
    473   1.4    bouyer 	struct nlm4_lockargs arg4;
    474   1.4    bouyer 
    475   1.4    bouyer 	nlmtonlm4(&arg->alock, &arg4.alock);
    476   1.4    bouyer 	arg4.cookie = arg->cookie;
    477   1.4    bouyer 	arg4.block = arg->block;
    478   1.4    bouyer 	arg4.exclusive = arg->exclusive;
    479   1.4    bouyer 	arg4.reclaim = arg->reclaim;
    480   1.4    bouyer 	arg4.state = arg->state;
    481   1.1    scottr 
    482   1.1    scottr 	if (debug_level)
    483   1.1    scottr 		log_from_addr("nlm_lock_msg", rqstp);
    484   1.1    scottr 
    485   1.9  christos 	result.cookie = arg->cookie;
    486   1.9  christos 	result.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON);
    487   1.9  christos 	transmit_result(NLM_LOCK_RES, &result,
    488  1.10      tron 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    489   1.1    scottr 
    490   1.9  christos 	return NULL;
    491   1.1    scottr }
    492   1.1    scottr 
    493   1.1    scottr /* nlm_cancel -------------------------------------------------------------- */
    494   1.1    scottr /*
    495   1.1    scottr  * Purpose:	Cancel a blocked lock request
    496   1.1    scottr  * Returns:	granted or denied
    497   1.1    scottr  * Notes:
    498   1.1    scottr  */
    499   1.1    scottr nlm_res *
    500   1.9  christos nlm_cancel_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
    501   1.1    scottr {
    502   1.9  christos 	static nlm_res result;
    503   1.4    bouyer 	struct nlm4_lock arg4;
    504   1.4    bouyer 
    505   1.4    bouyer 	nlmtonlm4(&arg->alock, &arg4);
    506   1.1    scottr 
    507   1.1    scottr 	if (debug_level)
    508   1.1    scottr 		log_from_addr("nlm_cancel", rqstp);
    509   1.1    scottr 
    510   1.1    scottr 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    511   1.9  christos 	result.cookie = arg->cookie;
    512   1.1    scottr 
    513   1.1    scottr 	/*
    514   1.1    scottr 	 * Since at present we never return 'nlm_blocked', there can never be
    515   1.1    scottr 	 * a lock to cancel, so this call always fails.
    516   1.1    scottr 	 */
    517   1.9  christos 	result.stat.stat = unlock(&arg4, LOCK_CANCEL);
    518   1.9  christos 	return &result;
    519   1.1    scottr }
    520   1.1    scottr 
    521   1.1    scottr void *
    522   1.9  christos nlm_cancel_msg_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
    523   1.1    scottr {
    524   1.9  christos 	static nlm_res result;
    525   1.4    bouyer 	struct nlm4_lock arg4;
    526   1.4    bouyer 
    527   1.4    bouyer 	nlmtonlm4(&arg->alock, &arg4);
    528   1.1    scottr 
    529   1.1    scottr 	if (debug_level)
    530   1.1    scottr 		log_from_addr("nlm_cancel_msg", rqstp);
    531   1.1    scottr 
    532   1.9  christos 	result.cookie = arg->cookie;
    533   1.1    scottr 	/*
    534   1.1    scottr 	 * Since at present we never return 'nlm_blocked', there can never be
    535   1.1    scottr 	 * a lock to cancel, so this call always fails.
    536   1.1    scottr 	 */
    537   1.9  christos 	result.stat.stat = unlock(&arg4, LOCK_CANCEL);
    538   1.9  christos 	transmit_result(NLM_CANCEL_RES, &result,
    539  1.10      tron 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    540   1.9  christos 	return NULL;
    541   1.1    scottr }
    542   1.1    scottr 
    543   1.1    scottr /* nlm_unlock -------------------------------------------------------------- */
    544   1.1    scottr /*
    545   1.1    scottr  * Purpose:	Release an existing lock
    546   1.1    scottr  * Returns:	Always granted, unless during grace period
    547   1.1    scottr  * Notes:	"no such lock" error condition is ignored, as the
    548   1.1    scottr  *		protocol uses unreliable UDP datagrams, and may well
    549   1.1    scottr  *		re-try an unlock that has already succeeded.
    550   1.1    scottr  */
    551   1.1    scottr nlm_res *
    552   1.9  christos nlm_unlock_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
    553   1.1    scottr {
    554   1.9  christos 	static nlm_res result;
    555   1.4    bouyer 	struct nlm4_lock arg4;
    556   1.4    bouyer 
    557   1.4    bouyer 	nlmtonlm4(&arg->alock, &arg4);
    558   1.1    scottr 
    559   1.1    scottr 	if (debug_level)
    560   1.1    scottr 		log_from_addr("nlm_unlock", rqstp);
    561   1.1    scottr 
    562   1.9  christos 	result.stat.stat = unlock(&arg4, 0);
    563   1.9  christos 	result.cookie = arg->cookie;
    564   1.1    scottr 
    565   1.9  christos 	return &result;
    566   1.1    scottr }
    567   1.1    scottr 
    568   1.1    scottr void *
    569   1.9  christos nlm_unlock_msg_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
    570   1.1    scottr {
    571   1.9  christos 	static nlm_res result;
    572   1.4    bouyer 	struct nlm4_lock arg4;
    573   1.4    bouyer 
    574   1.4    bouyer 	nlmtonlm4(&arg->alock, &arg4);
    575   1.1    scottr 
    576   1.1    scottr 	if (debug_level)
    577   1.1    scottr 		log_from_addr("nlm_unlock_msg", rqstp);
    578   1.1    scottr 
    579   1.9  christos 	result.stat.stat = unlock(&arg4, 0);
    580   1.9  christos 	result.cookie = arg->cookie;
    581   1.1    scottr 
    582   1.9  christos 	transmit_result(NLM_UNLOCK_RES, &result,
    583  1.10      tron 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    584   1.9  christos 	return NULL;
    585   1.1    scottr }
    586   1.1    scottr 
    587   1.1    scottr /* ------------------------------------------------------------------------- */
    588   1.1    scottr /*
    589   1.1    scottr  * Client-side pseudo-RPCs for results.  Note that for the client there
    590   1.1    scottr  * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
    591   1.1    scottr  * version returns the results in the RPC result, and so the client
    592   1.1    scottr  * does not normally receive incoming RPCs.
    593   1.1    scottr  *
    594   1.1    scottr  * The exception to this is nlm_granted(), which is genuinely an RPC
    595   1.1    scottr  * call from the server to the client - a 'call-back' in normal procedure
    596   1.1    scottr  * call terms.
    597   1.1    scottr  */
    598   1.1    scottr 
    599   1.1    scottr /* nlm_granted ------------------------------------------------------------- */
    600   1.1    scottr /*
    601   1.1    scottr  * Purpose:	Receive notification that formerly blocked lock now granted
    602   1.1    scottr  * Returns:	always success ('granted')
    603   1.1    scottr  * Notes:
    604   1.1    scottr  */
    605   1.1    scottr nlm_res *
    606   1.9  christos nlm_granted_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
    607   1.1    scottr {
    608   1.9  christos 	static nlm_res result;
    609   1.1    scottr 
    610   1.1    scottr 	if (debug_level)
    611   1.1    scottr 		log_from_addr("nlm_granted", rqstp);
    612   1.1    scottr 
    613   1.1    scottr 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    614   1.9  christos 	result.cookie = arg->cookie;
    615   1.1    scottr 
    616   1.9  christos 	result.stat.stat = nlm_granted;
    617   1.9  christos 	return &result;
    618   1.1    scottr }
    619   1.1    scottr 
    620   1.1    scottr void *
    621   1.9  christos nlm_granted_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
    622   1.1    scottr {
    623   1.9  christos 	static nlm_res result;
    624   1.1    scottr 
    625   1.1    scottr 	if (debug_level)
    626   1.1    scottr 		log_from_addr("nlm_granted_msg", rqstp);
    627   1.1    scottr 
    628   1.9  christos 	result.cookie = arg->cookie;
    629   1.9  christos 	result.stat.stat = nlm_granted;
    630   1.9  christos 	transmit_result(NLM_GRANTED_RES, &result,
    631  1.10      tron 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    632   1.9  christos 	return NULL;
    633   1.1    scottr }
    634   1.1    scottr 
    635   1.1    scottr /* nlm_test_res ------------------------------------------------------------ */
    636   1.1    scottr /*
    637   1.1    scottr  * Purpose:	Accept result from earlier nlm_test_msg() call
    638   1.1    scottr  * Returns:	Nothing
    639   1.1    scottr  */
    640   1.1    scottr void *
    641   1.9  christos /*ARGSUSED*/
    642   1.9  christos nlm_test_res_1_svc(nlm_testres *arg, struct svc_req *rqstp)
    643   1.1    scottr {
    644   1.1    scottr 	if (debug_level)
    645   1.1    scottr 		log_from_addr("nlm_test_res", rqstp);
    646   1.9  christos 	return NULL;
    647   1.1    scottr }
    648   1.1    scottr 
    649   1.1    scottr /* nlm_lock_res ------------------------------------------------------------ */
    650   1.1    scottr /*
    651   1.1    scottr  * Purpose:	Accept result from earlier nlm_lock_msg() call
    652   1.1    scottr  * Returns:	Nothing
    653   1.1    scottr  */
    654   1.1    scottr void *
    655   1.9  christos /*ARGSUSED*/
    656   1.9  christos nlm_lock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
    657   1.1    scottr {
    658   1.1    scottr 	if (debug_level)
    659   1.1    scottr 		log_from_addr("nlm_lock_res", rqstp);
    660   1.1    scottr 
    661   1.9  christos 	return NULL;
    662   1.1    scottr }
    663   1.1    scottr 
    664   1.1    scottr /* nlm_cancel_res ---------------------------------------------------------- */
    665   1.1    scottr /*
    666   1.1    scottr  * Purpose:	Accept result from earlier nlm_cancel_msg() call
    667   1.1    scottr  * Returns:	Nothing
    668   1.1    scottr  */
    669   1.1    scottr void *
    670   1.9  christos /*ARGSUSED*/
    671   1.9  christos nlm_cancel_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
    672   1.1    scottr {
    673   1.1    scottr 	if (debug_level)
    674   1.1    scottr 		log_from_addr("nlm_cancel_res", rqstp);
    675   1.9  christos 	return NULL;
    676   1.1    scottr }
    677   1.1    scottr 
    678   1.1    scottr /* nlm_unlock_res ---------------------------------------------------------- */
    679   1.1    scottr /*
    680   1.1    scottr  * Purpose:	Accept result from earlier nlm_unlock_msg() call
    681   1.1    scottr  * Returns:	Nothing
    682   1.1    scottr  */
    683   1.1    scottr void *
    684   1.9  christos /*ARGSUSED*/
    685   1.9  christos nlm_unlock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
    686   1.1    scottr {
    687   1.1    scottr 	if (debug_level)
    688   1.1    scottr 		log_from_addr("nlm_unlock_res", rqstp);
    689   1.9  christos 	return NULL;
    690   1.1    scottr }
    691   1.1    scottr 
    692   1.1    scottr /* nlm_granted_res --------------------------------------------------------- */
    693   1.1    scottr /*
    694   1.1    scottr  * Purpose:	Accept result from earlier nlm_granted_msg() call
    695   1.1    scottr  * Returns:	Nothing
    696   1.1    scottr  */
    697   1.1    scottr void *
    698   1.9  christos /*ARGSUSED*/
    699   1.9  christos nlm_granted_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
    700   1.1    scottr {
    701   1.1    scottr 	if (debug_level)
    702   1.1    scottr 		log_from_addr("nlm_granted_res", rqstp);
    703   1.9  christos 	return NULL;
    704   1.1    scottr }
    705   1.1    scottr 
    706   1.1    scottr /* ------------------------------------------------------------------------- */
    707   1.1    scottr /*
    708   1.1    scottr  * Calls for PCNFS locking (aka non-monitored locking, no involvement
    709   1.1    scottr  * of rpc.statd).
    710   1.1    scottr  *
    711   1.1    scottr  * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
    712   1.1    scottr  */
    713   1.1    scottr 
    714   1.1    scottr /* nlm_share --------------------------------------------------------------- */
    715   1.1    scottr /*
    716   1.1    scottr  * Purpose:	Establish a DOS-style lock
    717   1.1    scottr  * Returns:	success or failure
    718   1.1    scottr  * Notes:	Blocking locks are not supported - client is expected
    719   1.1    scottr  *		to retry if required.
    720   1.1    scottr  */
    721   1.1    scottr nlm_shareres *
    722   1.9  christos nlm_share_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
    723   1.1    scottr {
    724   1.9  christos 	static nlm_shareres result;
    725   1.1    scottr 
    726   1.1    scottr 	if (debug_level)
    727   1.1    scottr 		log_from_addr("nlm_share", rqstp);
    728   1.1    scottr 
    729   1.9  christos 	result.cookie = arg->cookie;
    730   1.9  christos 	result.stat = nlm_granted;
    731   1.9  christos 	result.sequence = 1234356;	/* X/Open says this field is ignored? */
    732   1.9  christos 	return &result;
    733   1.1    scottr }
    734   1.1    scottr 
    735   1.1    scottr /* nlm_unshare ------------------------------------------------------------ */
    736   1.1    scottr /*
    737   1.1    scottr  * Purpose:	Release a DOS-style lock
    738   1.1    scottr  * Returns:	nlm_granted, unless in grace period
    739   1.1    scottr  * Notes:
    740   1.1    scottr  */
    741   1.1    scottr nlm_shareres *
    742   1.9  christos nlm_unshare_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
    743   1.1    scottr {
    744   1.9  christos 	static nlm_shareres result;
    745   1.1    scottr 
    746   1.1    scottr 	if (debug_level)
    747   1.1    scottr 		log_from_addr("nlm_unshare", rqstp);
    748   1.1    scottr 
    749   1.9  christos 	result.cookie = arg->cookie;
    750   1.9  christos 	result.stat = nlm_granted;
    751   1.9  christos 	result.sequence = 1234356;	/* X/Open says this field is ignored? */
    752   1.9  christos 	return &result;
    753   1.1    scottr }
    754   1.1    scottr 
    755   1.1    scottr /* nlm_nm_lock ------------------------------------------------------------ */
    756   1.1    scottr /*
    757   1.1    scottr  * Purpose:	non-monitored version of nlm_lock()
    758   1.1    scottr  * Returns:	as for nlm_lock()
    759   1.1    scottr  * Notes:	These locks are in the same style as the standard nlm_lock,
    760   1.1    scottr  *		but the rpc.statd should not be called to establish a
    761   1.1    scottr  *		monitor for the client machine, since that machine is
    762   1.1    scottr  *		declared not to be running a rpc.statd, and so would not
    763   1.1    scottr  *		respond to the statd protocol.
    764   1.1    scottr  */
    765   1.1    scottr nlm_res *
    766   1.9  christos nlm_nm_lock_3_svc(nlm_lockargs *arg, struct svc_req *rqstp)
    767   1.1    scottr {
    768   1.9  christos 	static nlm_res result;
    769   1.1    scottr 
    770   1.1    scottr 	if (debug_level)
    771   1.1    scottr 		log_from_addr("nlm_nm_lock", rqstp);
    772   1.1    scottr 
    773   1.1    scottr 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    774   1.9  christos 	result.cookie = arg->cookie;
    775   1.9  christos 	result.stat.stat = nlm_granted;
    776   1.9  christos 	return &result;
    777   1.1    scottr }
    778   1.1    scottr 
    779   1.1    scottr /* nlm_free_all ------------------------------------------------------------ */
    780   1.1    scottr /*
    781   1.1    scottr  * Purpose:	Release all locks held by a named client
    782   1.1    scottr  * Returns:	Nothing
    783   1.1    scottr  * Notes:	Potential denial of service security problem here - the
    784   1.1    scottr  *		locks to be released are specified by a host name, independent
    785   1.1    scottr  *		of the address from which the request has arrived.
    786   1.1    scottr  *		Should probably be rejected if the named host has been
    787   1.1    scottr  *		using monitored locks.
    788   1.1    scottr  */
    789   1.1    scottr void *
    790   1.9  christos /*ARGSUSED*/
    791   1.9  christos nlm_free_all_3_svc(nlm_notify *arg, struct svc_req *rqstp)
    792   1.1    scottr {
    793   1.1    scottr 	static char dummy;
    794   1.1    scottr 
    795   1.1    scottr 	if (debug_level)
    796   1.1    scottr 		log_from_addr("nlm_free_all", rqstp);
    797   1.9  christos 	return &dummy;
    798   1.1    scottr }
    799   1.3    bouyer 
    800   1.3    bouyer /* calls for nlm version 4 (NFSv3) */
    801   1.3    bouyer /* nlm_test ---------------------------------------------------------------- */
    802   1.3    bouyer /*
    803   1.3    bouyer  * Purpose:	Test whether a specified lock would be granted if requested
    804   1.3    bouyer  * Returns:	nlm_granted (or error code)
    805   1.3    bouyer  * Notes:
    806   1.3    bouyer  */
    807   1.3    bouyer nlm4_testres *
    808   1.9  christos nlm4_test_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
    809   1.3    bouyer {
    810   1.9  christos 	static nlm4_testres result;
    811   1.4    bouyer 	struct nlm4_holder *holder;
    812   1.3    bouyer 
    813   1.3    bouyer 	if (debug_level)
    814   1.3    bouyer 		log_from_addr("nlm4_test", rqstp);
    815   1.3    bouyer 
    816   1.4    bouyer 	holder = testlock(&arg->alock, LOCK_V4);
    817   1.4    bouyer 
    818   1.3    bouyer 	/*
    819   1.3    bouyer 	 * Copy the cookie from the argument into the result.  Note that this
    820   1.3    bouyer 	 * is slightly hazardous, as the structure contains a pointer to a
    821   1.3    bouyer 	 * malloc()ed buffer that will get freed by the caller.  However, the
    822   1.3    bouyer 	 * main function transmits the result before freeing the argument
    823   1.3    bouyer 	 * so it is in fact safe.
    824   1.3    bouyer 	 */
    825   1.9  christos 	result.cookie = arg->cookie;
    826   1.4    bouyer 	if (holder == NULL) {
    827   1.9  christos 		result.stat.stat = nlm4_granted;
    828   1.4    bouyer 	} else {
    829   1.9  christos 		result.stat.stat = nlm4_denied;
    830   1.9  christos 		(void)memcpy(&result.stat.nlm4_testrply_u.holder, holder,
    831   1.4    bouyer 		    sizeof(struct nlm4_holder));
    832   1.4    bouyer 	}
    833   1.9  christos 	return &result;
    834   1.3    bouyer }
    835   1.3    bouyer 
    836   1.3    bouyer void *
    837   1.9  christos nlm4_test_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
    838   1.3    bouyer {
    839   1.9  christos 	nlm4_testres result;
    840   1.3    bouyer 	static char dummy;
    841   1.5      fvdl 	struct sockaddr *addr;
    842   1.3    bouyer 	CLIENT *cli;
    843   1.3    bouyer 	int success;
    844   1.3    bouyer 	struct timeval timeo;
    845   1.4    bouyer 	struct nlm4_holder *holder;
    846   1.3    bouyer 
    847   1.3    bouyer 	if (debug_level)
    848   1.3    bouyer 		log_from_addr("nlm4_test_msg", rqstp);
    849   1.3    bouyer 
    850   1.4    bouyer 	holder = testlock(&arg->alock, LOCK_V4);
    851   1.4    bouyer 
    852   1.9  christos 	result.cookie = arg->cookie;
    853   1.4    bouyer 	if (holder == NULL) {
    854   1.9  christos 		result.stat.stat = nlm4_granted;
    855   1.4    bouyer 	} else {
    856   1.9  christos 		result.stat.stat = nlm4_denied;
    857   1.9  christos 		(void)memcpy(&result.stat.nlm4_testrply_u.holder, holder,
    858   1.4    bouyer 		    sizeof(struct nlm4_holder));
    859   1.4    bouyer 	}
    860   1.3    bouyer 
    861   1.3    bouyer 	/*
    862   1.3    bouyer 	 * nlm_test has different result type to the other operations, so
    863   1.3    bouyer 	 * can't use transmit4_result() in this case
    864   1.3    bouyer 	 */
    865   1.5      fvdl 	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
    866   1.4    bouyer 	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
    867   1.3    bouyer 		timeo.tv_sec = 0; /* No timeout - not expecting response */
    868   1.3    bouyer 		timeo.tv_usec = 0;
    869   1.3    bouyer 
    870   1.3    bouyer 		success = clnt_call(cli, NLM4_TEST_RES, xdr_nlm4_testres,
    871   1.9  christos 		    &result, xdr_void, &dummy, timeo);
    872   1.3    bouyer 
    873   1.3    bouyer 		if (debug_level > 2)
    874   1.4    bouyer 			syslog(LOG_DEBUG, "clnt_call returns %d", success);
    875   1.3    bouyer 	}
    876   1.9  christos 	return NULL;
    877   1.3    bouyer }
    878   1.3    bouyer 
    879   1.3    bouyer /* nlm_lock ---------------------------------------------------------------- */
    880   1.3    bouyer /*
    881   1.3    bouyer  * Purposes:	Establish a lock
    882   1.3    bouyer  * Returns:	granted, denied or blocked
    883   1.3    bouyer  * Notes:	*** grace period support missing
    884   1.3    bouyer  */
    885   1.3    bouyer nlm4_res *
    886   1.9  christos nlm4_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
    887   1.3    bouyer {
    888   1.9  christos 	static nlm4_res result;
    889   1.3    bouyer 
    890   1.3    bouyer 	if (debug_level)
    891   1.3    bouyer 		log_from_addr("nlm4_lock", rqstp);
    892   1.3    bouyer 
    893   1.3    bouyer 	/* copy cookie from arg to result.  See comment in nlm_test_4() */
    894   1.9  christos 	result.cookie = arg->cookie;
    895   1.3    bouyer 
    896   1.9  christos 	result.stat.stat = (enum nlm4_stats)getlock(arg, rqstp,
    897   1.9  christos 	    LOCK_MON | LOCK_V4);
    898   1.9  christos 	return &result;
    899   1.3    bouyer }
    900   1.3    bouyer 
    901   1.3    bouyer void *
    902   1.9  christos nlm4_lock_msg_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
    903   1.3    bouyer {
    904   1.9  christos 	static nlm4_res result;
    905   1.3    bouyer 
    906   1.3    bouyer 	if (debug_level)
    907   1.3    bouyer 		log_from_addr("nlm4_lock_msg", rqstp);
    908   1.3    bouyer 
    909   1.9  christos 	result.cookie = arg->cookie;
    910   1.9  christos 	result.stat.stat = (enum nlm4_stats)getlock(arg, rqstp,
    911   1.9  christos 	    LOCK_MON | LOCK_ASYNC | LOCK_V4);
    912   1.9  christos 	transmit4_result(NLM4_LOCK_RES, &result,
    913  1.10      tron 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    914   1.3    bouyer 
    915   1.9  christos 	return NULL;
    916   1.3    bouyer }
    917   1.3    bouyer 
    918   1.3    bouyer /* nlm_cancel -------------------------------------------------------------- */
    919   1.3    bouyer /*
    920   1.3    bouyer  * Purpose:	Cancel a blocked lock request
    921   1.3    bouyer  * Returns:	granted or denied
    922   1.3    bouyer  * Notes:
    923   1.3    bouyer  */
    924   1.3    bouyer nlm4_res *
    925   1.9  christos nlm4_cancel_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
    926   1.3    bouyer {
    927   1.9  christos 	static nlm4_res result;
    928   1.3    bouyer 
    929   1.3    bouyer 	if (debug_level)
    930   1.3    bouyer 		log_from_addr("nlm4_cancel", rqstp);
    931   1.3    bouyer 
    932   1.3    bouyer 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
    933   1.9  christos 	result.cookie = arg->cookie;
    934   1.3    bouyer 
    935   1.3    bouyer 	/*
    936   1.3    bouyer 	 * Since at present we never return 'nlm_blocked', there can never be
    937   1.3    bouyer 	 * a lock to cancel, so this call always fails.
    938   1.3    bouyer 	 */
    939   1.9  christos 	result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_CANCEL);
    940   1.9  christos 	return &result;
    941   1.3    bouyer }
    942   1.3    bouyer 
    943   1.3    bouyer void *
    944   1.9  christos nlm4_cancel_msg_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
    945   1.3    bouyer {
    946   1.9  christos 	static nlm4_res result;
    947   1.3    bouyer 
    948   1.3    bouyer 	if (debug_level)
    949   1.3    bouyer 		log_from_addr("nlm4_cancel_msg", rqstp);
    950   1.3    bouyer 
    951   1.9  christos 	result.cookie = arg->cookie;
    952   1.3    bouyer 	/*
    953   1.3    bouyer 	 * Since at present we never return 'nlm_blocked', there can never be
    954   1.3    bouyer 	 * a lock to cancel, so this call always fails.
    955   1.3    bouyer 	 */
    956   1.9  christos 	result.stat.stat = (enum nlm4_stats)unlock(&arg->alock,
    957   1.9  christos 	    LOCK_CANCEL | LOCK_V4);
    958   1.9  christos 	transmit4_result(NLM4_CANCEL_RES, &result,
    959  1.10      tron 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    960   1.9  christos 	return NULL;
    961   1.3    bouyer }
    962   1.3    bouyer 
    963   1.3    bouyer /* nlm_unlock -------------------------------------------------------------- */
    964   1.3    bouyer /*
    965   1.3    bouyer  * Purpose:	Release an existing lock
    966   1.3    bouyer  * Returns:	Always granted, unless during grace period
    967   1.3    bouyer  * Notes:	"no such lock" error condition is ignored, as the
    968   1.3    bouyer  *		protocol uses unreliable UDP datagrams, and may well
    969   1.3    bouyer  *		re-try an unlock that has already succeeded.
    970   1.3    bouyer  */
    971   1.3    bouyer nlm4_res *
    972   1.9  christos nlm4_unlock_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
    973   1.3    bouyer {
    974   1.9  christos 	static nlm4_res result;
    975   1.3    bouyer 
    976   1.3    bouyer 	if (debug_level)
    977   1.3    bouyer 		log_from_addr("nlm4_unlock", rqstp);
    978   1.3    bouyer 
    979   1.9  christos 	result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_V4);
    980   1.9  christos 	result.cookie = arg->cookie;
    981   1.3    bouyer 
    982   1.9  christos 	return &result;
    983   1.3    bouyer }
    984   1.3    bouyer 
    985   1.3    bouyer void *
    986   1.9  christos nlm4_unlock_msg_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
    987   1.3    bouyer {
    988   1.9  christos 	static nlm4_res result;
    989   1.3    bouyer 
    990   1.3    bouyer 	if (debug_level)
    991   1.3    bouyer 		log_from_addr("nlm4_unlock_msg", rqstp);
    992   1.3    bouyer 
    993   1.9  christos 	result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_V4);
    994   1.9  christos 	result.cookie = arg->cookie;
    995   1.3    bouyer 
    996   1.9  christos 	transmit4_result(NLM4_UNLOCK_RES, &result,
    997  1.10      tron 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
    998   1.9  christos 	return NULL;
    999   1.3    bouyer }
   1000   1.3    bouyer 
   1001   1.3    bouyer /* ------------------------------------------------------------------------- */
   1002   1.3    bouyer /*
   1003   1.3    bouyer  * Client-side pseudo-RPCs for results.  Note that for the client there
   1004   1.3    bouyer  * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
   1005   1.3    bouyer  * version returns the results in the RPC result, and so the client
   1006   1.3    bouyer  * does not normally receive incoming RPCs.
   1007   1.3    bouyer  *
   1008   1.3    bouyer  * The exception to this is nlm_granted(), which is genuinely an RPC
   1009   1.3    bouyer  * call from the server to the client - a 'call-back' in normal procedure
   1010   1.3    bouyer  * call terms.
   1011   1.3    bouyer  */
   1012   1.3    bouyer 
   1013   1.3    bouyer /* nlm_granted ------------------------------------------------------------- */
   1014   1.3    bouyer /*
   1015   1.3    bouyer  * Purpose:	Receive notification that formerly blocked lock now granted
   1016   1.3    bouyer  * Returns:	always success ('granted')
   1017   1.3    bouyer  * Notes:
   1018   1.3    bouyer  */
   1019   1.3    bouyer nlm4_res *
   1020   1.9  christos nlm4_granted_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
   1021   1.3    bouyer {
   1022   1.9  christos 	static nlm4_res result;
   1023   1.3    bouyer 
   1024   1.3    bouyer 	if (debug_level)
   1025   1.3    bouyer 		log_from_addr("nlm4_granted", rqstp);
   1026   1.3    bouyer 
   1027   1.3    bouyer 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
   1028   1.9  christos 	result.cookie = arg->cookie;
   1029   1.3    bouyer 
   1030   1.9  christos 	result.stat.stat = nlm4_granted;
   1031   1.9  christos 	return &result;
   1032   1.3    bouyer }
   1033   1.3    bouyer 
   1034   1.3    bouyer void *
   1035   1.9  christos nlm4_granted_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
   1036   1.3    bouyer {
   1037   1.9  christos 	static nlm4_res result;
   1038   1.3    bouyer 
   1039   1.3    bouyer 	if (debug_level)
   1040   1.3    bouyer 		log_from_addr("nlm4_granted_msg", rqstp);
   1041   1.3    bouyer 
   1042   1.9  christos 	result.cookie = arg->cookie;
   1043   1.9  christos 	result.stat.stat = nlm4_granted;
   1044   1.9  christos 	transmit4_result(NLM4_GRANTED_RES, &result,
   1045   1.5      fvdl 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
   1046   1.9  christos 	return NULL;
   1047   1.3    bouyer }
   1048   1.3    bouyer 
   1049   1.3    bouyer /* nlm_test_res ------------------------------------------------------------ */
   1050   1.3    bouyer /*
   1051   1.3    bouyer  * Purpose:	Accept result from earlier nlm_test_msg() call
   1052   1.3    bouyer  * Returns:	Nothing
   1053   1.3    bouyer  */
   1054   1.3    bouyer void *
   1055   1.9  christos /*ARGSUSED*/
   1056   1.9  christos nlm4_test_res_4_svc(nlm4_testres *arg, struct svc_req *rqstp)
   1057   1.3    bouyer {
   1058   1.3    bouyer 	if (debug_level)
   1059   1.3    bouyer 		log_from_addr("nlm4_test_res", rqstp);
   1060   1.9  christos 	return NULL;
   1061   1.3    bouyer }
   1062   1.3    bouyer 
   1063   1.3    bouyer /* nlm_lock_res ------------------------------------------------------------ */
   1064   1.3    bouyer /*
   1065   1.3    bouyer  * Purpose:	Accept result from earlier nlm_lock_msg() call
   1066   1.3    bouyer  * Returns:	Nothing
   1067   1.3    bouyer  */
   1068   1.3    bouyer void *
   1069   1.9  christos /*ARGSUSED*/
   1070   1.9  christos nlm4_lock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
   1071   1.3    bouyer {
   1072   1.3    bouyer 	if (debug_level)
   1073   1.3    bouyer 		log_from_addr("nlm4_lock_res", rqstp);
   1074   1.3    bouyer 
   1075   1.9  christos 	return NULL;
   1076   1.3    bouyer }
   1077   1.3    bouyer 
   1078   1.3    bouyer /* nlm_cancel_res ---------------------------------------------------------- */
   1079   1.3    bouyer /*
   1080   1.3    bouyer  * Purpose:	Accept result from earlier nlm_cancel_msg() call
   1081   1.3    bouyer  * Returns:	Nothing
   1082   1.3    bouyer  */
   1083   1.3    bouyer void *
   1084   1.9  christos /*ARGSUSED*/
   1085   1.9  christos nlm4_cancel_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
   1086   1.3    bouyer {
   1087   1.3    bouyer 	if (debug_level)
   1088   1.3    bouyer 		log_from_addr("nlm4_cancel_res", rqstp);
   1089   1.9  christos 	return NULL;
   1090   1.3    bouyer }
   1091   1.3    bouyer 
   1092   1.3    bouyer /* nlm_unlock_res ---------------------------------------------------------- */
   1093   1.3    bouyer /*
   1094   1.3    bouyer  * Purpose:	Accept result from earlier nlm_unlock_msg() call
   1095   1.3    bouyer  * Returns:	Nothing
   1096   1.3    bouyer  */
   1097   1.3    bouyer void *
   1098   1.9  christos /*ARGSUSED*/
   1099   1.9  christos nlm4_unlock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
   1100   1.3    bouyer {
   1101   1.3    bouyer 	if (debug_level)
   1102   1.3    bouyer 		log_from_addr("nlm4_unlock_res", rqstp);
   1103   1.9  christos 	return NULL;
   1104   1.3    bouyer }
   1105   1.3    bouyer 
   1106   1.3    bouyer /* nlm_granted_res --------------------------------------------------------- */
   1107   1.3    bouyer /*
   1108   1.3    bouyer  * Purpose:	Accept result from earlier nlm_granted_msg() call
   1109   1.3    bouyer  * Returns:	Nothing
   1110   1.3    bouyer  */
   1111   1.3    bouyer void *
   1112   1.9  christos /*ARGSUSED*/
   1113   1.9  christos nlm4_granted_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
   1114   1.3    bouyer {
   1115   1.3    bouyer 	if (debug_level)
   1116   1.3    bouyer 		log_from_addr("nlm4_granted_res", rqstp);
   1117   1.9  christos 	return NULL;
   1118   1.3    bouyer }
   1119   1.3    bouyer 
   1120   1.3    bouyer /* ------------------------------------------------------------------------- */
   1121   1.3    bouyer /*
   1122   1.3    bouyer  * Calls for PCNFS locking (aka non-monitored locking, no involvement
   1123   1.3    bouyer  * of rpc.statd).
   1124   1.3    bouyer  *
   1125   1.3    bouyer  * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
   1126   1.3    bouyer  */
   1127   1.3    bouyer 
   1128   1.3    bouyer /* nlm_share --------------------------------------------------------------- */
   1129   1.3    bouyer /*
   1130   1.3    bouyer  * Purpose:	Establish a DOS-style lock
   1131   1.3    bouyer  * Returns:	success or failure
   1132   1.3    bouyer  * Notes:	Blocking locks are not supported - client is expected
   1133   1.3    bouyer  *		to retry if required.
   1134   1.3    bouyer  */
   1135   1.3    bouyer nlm4_shareres *
   1136   1.9  christos nlm4_share_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
   1137   1.3    bouyer {
   1138   1.9  christos 	static nlm4_shareres result;
   1139   1.3    bouyer 
   1140   1.3    bouyer 	if (debug_level)
   1141   1.3    bouyer 		log_from_addr("nlm4_share", rqstp);
   1142   1.3    bouyer 
   1143   1.9  christos 	result.cookie = arg->cookie;
   1144   1.9  christos 	result.stat = nlm4_granted;
   1145   1.9  christos 	result.sequence = 1234356;	/* X/Open says this field is ignored? */
   1146   1.9  christos 	return &result;
   1147   1.3    bouyer }
   1148   1.3    bouyer 
   1149   1.3    bouyer /* nlm4_unshare ------------------------------------------------------------ */
   1150   1.3    bouyer /*
   1151   1.3    bouyer  * Purpose:	Release a DOS-style lock
   1152   1.3    bouyer  * Returns:	nlm_granted, unless in grace period
   1153   1.3    bouyer  * Notes:
   1154   1.3    bouyer  */
   1155   1.3    bouyer nlm4_shareres *
   1156   1.9  christos nlm4_unshare_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
   1157   1.3    bouyer {
   1158   1.9  christos 	static nlm4_shareres result;
   1159   1.3    bouyer 
   1160   1.3    bouyer 	if (debug_level)
   1161   1.3    bouyer 		log_from_addr("nlm_unshare", rqstp);
   1162   1.3    bouyer 
   1163   1.9  christos 	result.cookie = arg->cookie;
   1164   1.9  christos 	result.stat = nlm4_granted;
   1165   1.9  christos 	result.sequence = 1234356;	/* X/Open says this field is ignored? */
   1166   1.9  christos 	return &result;
   1167   1.3    bouyer }
   1168   1.3    bouyer 
   1169   1.3    bouyer /* nlm4_nm_lock ------------------------------------------------------------ */
   1170   1.3    bouyer /*
   1171   1.3    bouyer  * Purpose:	non-monitored version of nlm4_lock()
   1172   1.3    bouyer  * Returns:	as for nlm4_lock()
   1173   1.3    bouyer  * Notes:	These locks are in the same style as the standard nlm4_lock,
   1174   1.3    bouyer  *		but the rpc.statd should not be called to establish a
   1175   1.3    bouyer  *		monitor for the client machine, since that machine is
   1176   1.3    bouyer  *		declared not to be running a rpc.statd, and so would not
   1177   1.3    bouyer  *		respond to the statd protocol.
   1178   1.3    bouyer  */
   1179   1.3    bouyer nlm4_res *
   1180   1.9  christos nlm4_nm_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
   1181   1.3    bouyer {
   1182   1.9  christos 	static nlm4_res result;
   1183   1.3    bouyer 
   1184   1.3    bouyer 	if (debug_level)
   1185   1.3    bouyer 		log_from_addr("nlm4_nm_lock", rqstp);
   1186   1.3    bouyer 
   1187   1.3    bouyer 	/* copy cookie from arg to result.  See comment in nlm4_test_1() */
   1188   1.9  christos 	result.cookie = arg->cookie;
   1189   1.9  christos 	result.stat.stat = nlm4_granted;
   1190   1.9  christos 	return &result;
   1191   1.3    bouyer }
   1192   1.3    bouyer 
   1193   1.3    bouyer /* nlm4_free_all ------------------------------------------------------------ */
   1194   1.3    bouyer /*
   1195   1.3    bouyer  * Purpose:	Release all locks held by a named client
   1196   1.3    bouyer  * Returns:	Nothing
   1197   1.3    bouyer  * Notes:	Potential denial of service security problem here - the
   1198   1.3    bouyer  *		locks to be released are specified by a host name, independent
   1199   1.3    bouyer  *		of the address from which the request has arrived.
   1200   1.3    bouyer  *		Should probably be rejected if the named host has been
   1201   1.3    bouyer  *		using monitored locks.
   1202   1.3    bouyer  */
   1203   1.3    bouyer void *
   1204   1.9  christos /*ARGSUSED*/
   1205   1.9  christos nlm4_free_all_4_svc(nlm_notify *arg, struct svc_req *rqstp)
   1206   1.3    bouyer {
   1207   1.3    bouyer 	static char dummy;
   1208   1.3    bouyer 
   1209   1.3    bouyer 	if (debug_level)
   1210   1.3    bouyer 		log_from_addr("nlm4_free_all", rqstp);
   1211   1.9  christos 	return &dummy;
   1212   1.3    bouyer }
   1213   1.3    bouyer 
   1214   1.4    bouyer /* nlm_sm_notify --------------------------------------------------------- */
   1215   1.4    bouyer /*
   1216   1.4    bouyer  * Purpose:	called by rpc.statd when a monitored host state changes.
   1217   1.4    bouyer  * Returns:	Nothing
   1218   1.4    bouyer  */
   1219   1.4    bouyer void *
   1220   1.9  christos /*ARGSUSED*/
   1221   1.9  christos nlm_sm_notify_0_svc(struct nlm_sm_status *arg, struct svc_req *rqstp)
   1222   1.4    bouyer {
   1223   1.4    bouyer 	static char dummy;
   1224   1.4    bouyer 	notify(arg->mon_name, arg->state);
   1225   1.9  christos 	return &dummy;
   1226   1.4    bouyer }
   1227