174462Salfred/*	$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $	*/
274462Salfred/*	$FreeBSD$ */
374462Salfred/*
474462Salfred * Copyright (c) 1995
574462Salfred *	A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
674462Salfred *
774462Salfred * Redistribution and use in source and binary forms, with or without
874462Salfred * modification, are permitted provided that the following conditions
974462Salfred * are met:
1074462Salfred * 1. Redistributions of source code must retain the above copyright
1174462Salfred *    notice, this list of conditions and the following disclaimer.
1274462Salfred * 2. Redistributions in binary form must reproduce the above copyright
1374462Salfred *    notice, this list of conditions and the following disclaimer in the
1474462Salfred *    documentation and/or other materials provided with the distribution.
1574462Salfred * 3. All advertising materials mentioning features or use of this software
1674462Salfred *    must display the following acknowledgement:
1774462Salfred *	This product includes software developed for the FreeBSD project
1874462Salfred * 4. Neither the name of the author nor the names of any co-contributors
1974462Salfred *    may be used to endorse or promote products derived from this software
2074462Salfred *    without specific prior written permission.
2174462Salfred *
2274462Salfred * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
2374462Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2474462Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2574462Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2674462Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2774462Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2874462Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2974462Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3074462Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3174462Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3274462Salfred * SUCH DAMAGE.
3374462Salfred *
3474462Salfred */
3574462Salfred
3674462Salfred#include <sys/cdefs.h>
3774462Salfred#ifndef lint
3874462Salfred__RCSID("$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $");
3974462Salfred#endif
4074462Salfred
4174462Salfred#include <sys/param.h>
4274462Salfred#include <sys/socket.h>
4374462Salfred
4474462Salfred#include <netinet/in.h>
4574462Salfred#include <arpa/inet.h>
4674462Salfred
4774462Salfred#include <netdb.h>
4874462Salfred#include <stdio.h>
4974462Salfred#include <string.h>
5074462Salfred#include <syslog.h>
51136320Sstefanf#include <unistd.h>
5274462Salfred#include <netconfig.h>
5374462Salfred
5474462Salfred#include <rpc/rpc.h>
5574462Salfred#include <rpcsvc/sm_inter.h>
5674462Salfred
5774462Salfred#include "lockd.h"
5874462Salfred#include <rpcsvc/nlm_prot.h>
5974462Salfred#include "lockd_lock.h"
6074462Salfred
6174462Salfred
6274462Salfred#define	CLIENT_CACHE_SIZE	64	/* No. of client sockets cached */
6374462Salfred#define	CLIENT_CACHE_LIFETIME	120	/* In seconds */
6474462Salfred
65141217Skuriyama#define	getrpcaddr(rqstp)	(struct sockaddr *)(svc_getrpccaller((rqstp)->rq_xprt)->buf)
66141217Skuriyama
6792969Salfredstatic void	log_from_addr(const char *, struct svc_req *);
6892909Salfredstatic void	log_netobj(netobj *obj);
6992909Salfredstatic int	addrcmp(struct sockaddr *, struct sockaddr *);
7074462Salfred
7174462Salfred/* log_from_addr ----------------------------------------------------------- */
7274462Salfred/*
7374462Salfred * Purpose:	Log name of function called and source address
7474462Salfred * Returns:	Nothing
7574462Salfred * Notes:	Extracts the source address from the transport handle
7674462Salfred *		passed in as part of the called procedure specification
7774462Salfred */
7874462Salfredstatic void
7974462Salfredlog_from_addr(fun_name, req)
8092969Salfred	const char *fun_name;
8174462Salfred	struct svc_req *req;
8274462Salfred{
8374462Salfred	struct sockaddr *addr;
8474462Salfred	char hostname_buf[NI_MAXHOST];
8574462Salfred
8674462Salfred	addr = svc_getrpccaller(req->rq_xprt)->buf;
8774462Salfred	if (getnameinfo(addr , addr->sa_len, hostname_buf, sizeof hostname_buf,
8874462Salfred	    NULL, 0, 0) != 0)
8974462Salfred		return;
9074462Salfred
9174462Salfred	syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
9274462Salfred}
9374462Salfred
9484923Salfred/* log_netobj ----------------------------------------------------------- */
9584923Salfred/*
9684923Salfred * Purpose:	Log a netobj
9784923Salfred * Returns:	Nothing
9884923Salfred * Notes:	This function should only really be called as part of
9984923Salfred *  		a debug subsystem.
10084923Salfred*/
10184923Salfredstatic void
10284923Salfredlog_netobj(obj)
10384923Salfred	netobj *obj;
10484923Salfred{
10584923Salfred	char objvalbuffer[(sizeof(char)*2)*MAX_NETOBJ_SZ+2];
10684923Salfred	char objascbuffer[sizeof(char)*MAX_NETOBJ_SZ+1];
10786319Salfred	unsigned int i, maxlen;
10884923Salfred	char *tmp1, *tmp2;
10984923Salfred
11084923Salfred	/* Notify of potential security attacks */
11184923Salfred	if (obj->n_len > MAX_NETOBJ_SZ)	{
11284923Salfred		syslog(LOG_DEBUG, "SOMEONE IS TRYING TO DO SOMETHING NASTY!\n");
11384923Salfred		syslog(LOG_DEBUG, "netobj too large! Should be %d was %d\n",
11484923Salfred		    MAX_NETOBJ_SZ, obj->n_len);
11584923Salfred	}
11684923Salfred	/* Prevent the security hazard from the buffer overflow */
11784923Salfred	maxlen = (obj->n_len < MAX_NETOBJ_SZ ? obj->n_len : MAX_NETOBJ_SZ);
11884923Salfred	for (i=0, tmp1 = objvalbuffer, tmp2 = objascbuffer; i < obj->n_len;
11984923Salfred	    i++, tmp1 +=2, tmp2 +=1) {
12084923Salfred		sprintf(tmp1,"%02X",*(obj->n_bytes+i));
12184923Salfred		sprintf(tmp2,"%c",*(obj->n_bytes+i));
12284923Salfred	}
12384923Salfred	*tmp1 = '\0';
12484923Salfred	*tmp2 = '\0';
12584923Salfred	syslog(LOG_DEBUG,"netobjvals: %s\n",objvalbuffer);
12684923Salfred	syslog(LOG_DEBUG,"netobjascs: %s\n",objascbuffer);
12784923Salfred}
12874462Salfred/* get_client -------------------------------------------------------------- */
12974462Salfred/*
13074462Salfred * Purpose:	Get a CLIENT* for making RPC calls to lockd on given host
13174462Salfred * Returns:	CLIENT* pointer, from clnt_udp_create, or NULL if error
13274462Salfred * Notes:	Creating a CLIENT* is quite expensive, involving a
13374462Salfred *		conversation with the remote portmapper to get the
13474462Salfred *		port number.  Since a given client is quite likely
13574462Salfred *		to make several locking requests in succession, it is
13674462Salfred *		desirable to cache the created CLIENT*.
13774462Salfred *
13874462Salfred *		Since we are using UDP rather than TCP, there is no cost
13974462Salfred *		to the remote system in keeping these cached indefinitely.
14074462Salfred *		Unfortunately there is a snag: if the remote system
14174462Salfred *		reboots, the cached portmapper results will be invalid,
14274462Salfred *		and we will never detect this since all of the xxx_msg()
14374462Salfred *		calls return no result - we just fire off a udp packet
14474462Salfred *		and hope for the best.
14574462Salfred *
14674462Salfred *		We solve this by discarding cached values after two
14774462Salfred *		minutes, regardless of whether they have been used
14874462Salfred *		in the meanwhile (since a bad one might have been used
14974462Salfred *		plenty of times, as the host keeps retrying the request
15074462Salfred *		and we keep sending the reply back to the wrong port).
15174462Salfred *
15274462Salfred *		Given that the entries will always expire in the order
15374462Salfred *		that they were created, there is no point in a LRU
15474462Salfred *		algorithm for when the cache gets full - entries are
15574462Salfred *		always re-used in sequence.
15674462Salfred */
15774462Salfredstatic CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
15874462Salfredstatic long clnt_cache_time[CLIENT_CACHE_SIZE];	/* time entry created */
15974462Salfredstatic struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE];
16076093Salfredstatic rpcvers_t clnt_cache_vers[CLIENT_CACHE_SIZE];
16174462Salfredstatic int clnt_cache_next_to_use = 0;
16274462Salfred
16374462Salfredstatic int
16474462Salfredaddrcmp(sa1, sa2)
16574462Salfred	struct sockaddr *sa1;
16674462Salfred	struct sockaddr *sa2;
16774462Salfred{
16874462Salfred	int len;
16974462Salfred	void *p1, *p2;
17074462Salfred
17174462Salfred	if (sa1->sa_family != sa2->sa_family)
17274462Salfred		return -1;
17374462Salfred
17474462Salfred	switch (sa1->sa_family) {
17574462Salfred	case AF_INET:
17674462Salfred		p1 = &((struct sockaddr_in *)sa1)->sin_addr;
17774462Salfred		p2 = &((struct sockaddr_in *)sa2)->sin_addr;
17874462Salfred		len = 4;
17974462Salfred		break;
18074462Salfred	case AF_INET6:
18174462Salfred		p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
18274462Salfred		p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
18374462Salfred		len = 16;
18474462Salfred		break;
18574462Salfred	default:
18674462Salfred		return -1;
18774462Salfred	}
18874462Salfred
18974462Salfred	return memcmp(p1, p2, len);
19074462Salfred}
19174462Salfred
19274462SalfredCLIENT *
19374462Salfredget_client(host_addr, vers)
19474462Salfred	struct sockaddr *host_addr;
19574462Salfred	rpcvers_t vers;
19674462Salfred{
19774462Salfred	CLIENT *client;
19874462Salfred	struct timeval retry_time, time_now;
199141217Skuriyama	int error, i;
20092977Salfred	const char *netid;
20174462Salfred	struct netconfig *nconf;
20274462Salfred	char host[NI_MAXHOST];
203126606Sroam	uid_t old_euid;
204126606Sroam	int clnt_fd;
20574462Salfred
20674462Salfred	gettimeofday(&time_now, NULL);
20774462Salfred
20874462Salfred	/*
20974462Salfred	 * Search for the given client in the cache, zapping any expired
21074462Salfred	 * entries that we happen to notice in passing.
21174462Salfred	 */
21274462Salfred	for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
21374462Salfred		client = clnt_cache_ptr[i];
21474462Salfred		if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
21574462Salfred		    < time_now.tv_sec)) {
21674462Salfred			/* Cache entry has expired. */
21774462Salfred			if (debug_level > 3)
21874462Salfred				syslog(LOG_DEBUG, "Expired CLIENT* in cache");
21974462Salfred			clnt_cache_time[i] = 0L;
22074462Salfred			clnt_destroy(client);
22174462Salfred			clnt_cache_ptr[i] = NULL;
22274462Salfred			client = NULL;
22374462Salfred		}
22474462Salfred		if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i],
22576093Salfred		    host_addr) && clnt_cache_vers[i] == vers) {
22674462Salfred			/* Found it! */
22774462Salfred			if (debug_level > 3)
22874462Salfred				syslog(LOG_DEBUG, "Found CLIENT* in cache");
22974462Salfred			return (client);
23074462Salfred		}
23174462Salfred	}
23274462Salfred
23376093Salfred	if (debug_level > 3)
23476093Salfred		syslog(LOG_DEBUG, "CLIENT* not found in cache, creating");
23576093Salfred
23674462Salfred	/* Not found in cache.  Free the next entry if it is in use. */
23774462Salfred	if (clnt_cache_ptr[clnt_cache_next_to_use]) {
23874462Salfred		clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
23974462Salfred		clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
24074462Salfred	}
24174462Salfred
24274462Salfred	/*
24374462Salfred	 * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
24474462Salfred	 * to avoid DNS lookups.
24574462Salfred	 */
246141217Skuriyama	error = getnameinfo(host_addr, host_addr->sa_len, host, sizeof host,
247141217Skuriyama			    NULL, 0, NI_NUMERICHOST);
248141217Skuriyama	if (error != 0) {
249141217Skuriyama		syslog(LOG_ERR, "unable to get name string for caller: %s",
250141217Skuriyama		       gai_strerror(error));
25174462Salfred		return NULL;
25274462Salfred	}
25374462Salfred
25474462Salfred#if 1
25574462Salfred	if (host_addr->sa_family == AF_INET6)
25674462Salfred		netid = "udp6";
25774462Salfred	else
25874462Salfred		netid = "udp";
25974462Salfred#else
26074462Salfred	if (host_addr->sa_family == AF_INET6)
26174462Salfred		netid = "tcp6";
26274462Salfred	else
26374462Salfred		netid = "tcp";
26474462Salfred#endif
26574462Salfred	nconf = getnetconfigent(netid);
26674462Salfred	if (nconf == NULL) {
26774462Salfred		syslog(LOG_ERR, "could not get netconfig info for '%s': "
26874462Salfred				"no /etc/netconfig file?", netid);
26974462Salfred		return NULL;
27074462Salfred	}
27174462Salfred
27274462Salfred	client = clnt_tp_create(host, NLM_PROG, vers, nconf);
27374462Salfred	freenetconfigent(nconf);
27474462Salfred
27574462Salfred	if (!client) {
27674462Salfred		syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create"));
27774462Salfred		syslog(LOG_ERR, "Unable to return result to %s", host);
27874462Salfred		return NULL;
27974462Salfred	}
28074462Salfred
281126606Sroam	/* Get the FD of the client, for bindresvport. */
282126606Sroam	clnt_control(client, CLGET_FD, &clnt_fd);
283126606Sroam
284126606Sroam	/* Regain root privileges, for bindresvport. */
285126606Sroam	old_euid = geteuid();
286126606Sroam	seteuid(0);
287126606Sroam
288126606Sroam	/*
289126606Sroam	 * Bind the client FD to a reserved port.
290126606Sroam	 * Some NFS servers reject any NLM request from a non-reserved port.
291126606Sroam	 */
292126606Sroam	bindresvport(clnt_fd, NULL);
293126606Sroam
294126606Sroam	/* Drop root privileges again. */
295126606Sroam	seteuid(old_euid);
296126606Sroam
29774462Salfred	/* Success - update the cache entry */
29874462Salfred	clnt_cache_ptr[clnt_cache_next_to_use] = client;
29974462Salfred	memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
30074462Salfred	    host_addr->sa_len);
30176093Salfred	clnt_cache_vers[clnt_cache_next_to_use] = vers;
30274462Salfred	clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
303132254Smr	if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE)
30474462Salfred		clnt_cache_next_to_use = 0;
30574462Salfred
30674462Salfred	/*
30774462Salfred	 * Disable the default timeout, so we can specify our own in calls
30874462Salfred	 * to clnt_call().  (Note that the timeout is a different concept
30974462Salfred	 * from the retry period set in clnt_udp_create() above.)
31074462Salfred	 */
31174462Salfred	retry_time.tv_sec = -1;
31274462Salfred	retry_time.tv_usec = -1;
31374462Salfred	clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
31474462Salfred
31574462Salfred	if (debug_level > 3)
31674462Salfred		syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
31774462Salfred	return client;
31874462Salfred}
31974462Salfred
32074462Salfred
32174462Salfred/* transmit_result --------------------------------------------------------- */
32274462Salfred/*
32374462Salfred * Purpose:	Transmit result for nlm_xxx_msg pseudo-RPCs
32474462Salfred * Returns:	Nothing - we have no idea if the datagram got there
32574462Salfred * Notes:	clnt_call() will always fail (with timeout) as we are
32674462Salfred *		calling it with timeout 0 as a hack to just issue a datagram
32774462Salfred *		without expecting a result
32874462Salfred */
32974462Salfredvoid
33074462Salfredtransmit_result(opcode, result, addr)
33174462Salfred	int opcode;
33274462Salfred	nlm_res *result;
33374462Salfred	struct sockaddr *addr;
33474462Salfred{
33574462Salfred	static char dummy;
33674462Salfred	CLIENT *cli;
33774462Salfred	struct timeval timeo;
33874462Salfred	int success;
33974462Salfred
34074462Salfred	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
34174462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
34274462Salfred		timeo.tv_usec = 0;
34374462Salfred
344121558Speter		success = clnt_call(cli, opcode, (xdrproc_t)xdr_nlm_res, result,
345121558Speter		    (xdrproc_t)xdr_void, &dummy, timeo);
34674462Salfred
34774462Salfred		if (debug_level > 2)
34874462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
34974462Salfred			    success, clnt_sperrno(success));
35074462Salfred	}
35174462Salfred}
35274462Salfred/* transmit4_result --------------------------------------------------------- */
35374462Salfred/*
35474462Salfred * Purpose:	Transmit result for nlm4_xxx_msg pseudo-RPCs
35574462Salfred * Returns:	Nothing - we have no idea if the datagram got there
35674462Salfred * Notes:	clnt_call() will always fail (with timeout) as we are
35774462Salfred *		calling it with timeout 0 as a hack to just issue a datagram
35874462Salfred *		without expecting a result
35974462Salfred */
36074462Salfredvoid
36174462Salfredtransmit4_result(opcode, result, addr)
36274462Salfred	int opcode;
36374462Salfred	nlm4_res *result;
36474462Salfred	struct sockaddr *addr;
36574462Salfred{
36674462Salfred	static char dummy;
36774462Salfred	CLIENT *cli;
36874462Salfred	struct timeval timeo;
36974462Salfred	int success;
37074462Salfred
37174462Salfred	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
37274462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
37374462Salfred		timeo.tv_usec = 0;
37474462Salfred
375121558Speter		success = clnt_call(cli, opcode,
376121558Speter		    (xdrproc_t)xdr_nlm4_res, result,
377121558Speter		    (xdrproc_t)xdr_void, &dummy, timeo);
37874462Salfred
37974462Salfred		if (debug_level > 2)
38074462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
38174462Salfred			    success, clnt_sperrno(success));
38274462Salfred	}
38374462Salfred}
38474462Salfred
38574462Salfred/*
38674462Salfred * converts a struct nlm_lock to struct nlm4_lock
38774462Salfred */
38892909Salfredstatic void nlmtonlm4(struct nlm_lock *, struct nlm4_lock *);
38974462Salfredstatic void
39074462Salfrednlmtonlm4(arg, arg4)
39174462Salfred	struct nlm_lock *arg;
39274462Salfred	struct nlm4_lock *arg4;
39374462Salfred{
394132254Smr	arg4->caller_name = arg->caller_name;
395132254Smr	arg4->fh = arg->fh;
396132254Smr	arg4->oh = arg->oh;
397132254Smr	arg4->svid = arg->svid;
39874462Salfred	arg4->l_offset = arg->l_offset;
39974462Salfred	arg4->l_len = arg->l_len;
40074462Salfred}
40174462Salfred/* ------------------------------------------------------------------------- */
40274462Salfred/*
40374462Salfred * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
40474462Salfred * involved to ensure reclaim of locks after a crash of the "stateless"
40574462Salfred * server.
40674462Salfred *
40774462Salfred * These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
40874462Salfred * The first are standard RPCs with argument and result.
40974462Salfred * The nlm_xxx_msg() calls implement exactly the same functions, but
41074462Salfred * use two pseudo-RPCs (one in each direction).  These calls are NOT
41174462Salfred * standard use of the RPC protocol in that they do not return a result
41274462Salfred * at all (NB. this is quite different from returning a void result).
41374462Salfred * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
41474462Salfred * datagrams, requiring higher-level code to perform retries.
41574462Salfred *
41674462Salfred * Despite the disadvantages of the nlm_xxx_msg() approach (some of which
41774462Salfred * are documented in the comments to get_client() above), this is the
41874462Salfred * interface used by all current commercial NFS implementations
41974462Salfred * [Solaris, SCO, AIX etc.].  This is presumed to be because these allow
42074462Salfred * implementations to continue using the standard RPC libraries, while
42174462Salfred * avoiding the block-until-result nature of the library interface.
42274462Salfred *
42374462Salfred * No client implementations have been identified so far that make use
42474462Salfred * of the true RPC version (early SunOS releases would be a likely candidate
42574462Salfred * for testing).
42674462Salfred */
42774462Salfred
42874462Salfred/* nlm_test ---------------------------------------------------------------- */
42974462Salfred/*
43074462Salfred * Purpose:	Test whether a specified lock would be granted if requested
43174462Salfred * Returns:	nlm_granted (or error code)
43274462Salfred * Notes:
43374462Salfred */
43474462Salfrednlm_testres *
43574462Salfrednlm_test_1_svc(arg, rqstp)
43674462Salfred	nlm_testargs *arg;
43774462Salfred	struct svc_req *rqstp;
43874462Salfred{
43974462Salfred	static nlm_testres res;
44074462Salfred	struct nlm4_lock arg4;
44174462Salfred	struct nlm4_holder *holder;
44274462Salfred	nlmtonlm4(&arg->alock, &arg4);
44374462Salfred
44474462Salfred	if (debug_level)
44574462Salfred		log_from_addr("nlm_test", rqstp);
44674462Salfred
44784923Salfred	holder = testlock(&arg4, arg->exclusive, 0);
44874462Salfred	/*
44974462Salfred	 * Copy the cookie from the argument into the result.  Note that this
45074462Salfred	 * is slightly hazardous, as the structure contains a pointer to a
45174462Salfred	 * malloc()ed buffer that will get freed by the caller.  However, the
45274462Salfred	 * main function transmits the result before freeing the argument
45374462Salfred	 * so it is in fact safe.
45474462Salfred	 */
45574462Salfred	res.cookie = arg->cookie;
45674462Salfred	if (holder == NULL) {
45774462Salfred		res.stat.stat = nlm_granted;
45874462Salfred	} else {
45974462Salfred		res.stat.stat = nlm_denied;
46074462Salfred		memcpy(&res.stat.nlm_testrply_u.holder, holder,
46174462Salfred		    sizeof(struct nlm_holder));
46274462Salfred		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
46374462Salfred		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
46474462Salfred	}
46574462Salfred	return (&res);
46674462Salfred}
46774462Salfred
46874462Salfredvoid *
46974462Salfrednlm_test_msg_1_svc(arg, rqstp)
47074462Salfred	nlm_testargs *arg;
47174462Salfred	struct svc_req *rqstp;
47274462Salfred{
47374462Salfred	nlm_testres res;
47474462Salfred	static char dummy;
47574462Salfred	struct sockaddr *addr;
47674462Salfred	CLIENT *cli;
47774462Salfred	int success;
47874462Salfred	struct timeval timeo;
47974462Salfred	struct nlm4_lock arg4;
48074462Salfred	struct nlm4_holder *holder;
48174462Salfred
48274462Salfred	nlmtonlm4(&arg->alock, &arg4);
48374462Salfred
48474462Salfred	if (debug_level)
48574462Salfred		log_from_addr("nlm_test_msg", rqstp);
48674462Salfred
48784923Salfred	holder = testlock(&arg4, arg->exclusive, 0);
48874462Salfred
48974462Salfred	res.cookie = arg->cookie;
49074462Salfred	if (holder == NULL) {
49174462Salfred		res.stat.stat = nlm_granted;
49274462Salfred	} else {
49374462Salfred		res.stat.stat = nlm_denied;
49474462Salfred		memcpy(&res.stat.nlm_testrply_u.holder, holder,
49574462Salfred		    sizeof(struct nlm_holder));
49674462Salfred		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
49774462Salfred		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
49874462Salfred	}
49974462Salfred
50074462Salfred	/*
50174462Salfred	 * nlm_test has different result type to the other operations, so
50274462Salfred	 * can't use transmit_result() in this case
50374462Salfred	 */
50474462Salfred	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
50574462Salfred	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
50674462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
50774462Salfred		timeo.tv_usec = 0;
50874462Salfred
509121558Speter		success = clnt_call(cli, NLM_TEST_RES,
510121558Speter		    (xdrproc_t)xdr_nlm_testres, &res,
511121558Speter		    (xdrproc_t)xdr_void, &dummy, timeo);
51274462Salfred
51374462Salfred		if (debug_level > 2)
51474462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d", success);
51574462Salfred	}
51674462Salfred	return (NULL);
51774462Salfred}
51874462Salfred
51974462Salfred/* nlm_lock ---------------------------------------------------------------- */
52074462Salfred/*
52174462Salfred * Purposes:	Establish a lock
52274462Salfred * Returns:	granted, denied or blocked
52374462Salfred * Notes:	*** grace period support missing
52474462Salfred */
52574462Salfrednlm_res *
52674462Salfrednlm_lock_1_svc(arg, rqstp)
52774462Salfred	nlm_lockargs *arg;
52874462Salfred	struct svc_req *rqstp;
52974462Salfred{
53074462Salfred	static nlm_res res;
53174462Salfred	struct nlm4_lockargs arg4;
53274462Salfred	nlmtonlm4(&arg->alock, &arg4.alock);
53374462Salfred	arg4.cookie = arg->cookie;
53474462Salfred	arg4.block = arg->block;
53574462Salfred	arg4.exclusive = arg->exclusive;
53674462Salfred	arg4.reclaim = arg->reclaim;
53774462Salfred	arg4.state = arg->state;
53874462Salfred
53974462Salfred	if (debug_level)
54074462Salfred		log_from_addr("nlm_lock", rqstp);
54174462Salfred
54274462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
54374462Salfred	res.cookie = arg->cookie;
54474462Salfred
54574462Salfred	res.stat.stat = getlock(&arg4, rqstp, LOCK_MON);
54674462Salfred	return (&res);
54774462Salfred}
54874462Salfred
54974462Salfredvoid *
55074462Salfrednlm_lock_msg_1_svc(arg, rqstp)
55174462Salfred	nlm_lockargs *arg;
55274462Salfred	struct svc_req *rqstp;
55374462Salfred{
55474462Salfred	static nlm_res res;
55574462Salfred	struct nlm4_lockargs arg4;
55674462Salfred
55774462Salfred	nlmtonlm4(&arg->alock, &arg4.alock);
55874462Salfred	arg4.cookie = arg->cookie;
55974462Salfred	arg4.block = arg->block;
56074462Salfred	arg4.exclusive = arg->exclusive;
56174462Salfred	arg4.reclaim = arg->reclaim;
56274462Salfred	arg4.state = arg->state;
56374462Salfred
56474462Salfred	if (debug_level)
56574462Salfred		log_from_addr("nlm_lock_msg", rqstp);
56674462Salfred
56774462Salfred	res.cookie = arg->cookie;
56874462Salfred	res.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON);
569141217Skuriyama	transmit_result(NLM_LOCK_RES, &res, getrpcaddr(rqstp));
57074462Salfred
57174462Salfred	return (NULL);
57274462Salfred}
57374462Salfred
57474462Salfred/* nlm_cancel -------------------------------------------------------------- */
57574462Salfred/*
57674462Salfred * Purpose:	Cancel a blocked lock request
57774462Salfred * Returns:	granted or denied
57874462Salfred * Notes:
57974462Salfred */
58074462Salfrednlm_res *
58174462Salfrednlm_cancel_1_svc(arg, rqstp)
58274462Salfred	nlm_cancargs *arg;
58374462Salfred	struct svc_req *rqstp;
58474462Salfred{
58574462Salfred	static nlm_res res;
58674462Salfred	struct nlm4_lock arg4;
58774462Salfred
58874462Salfred	nlmtonlm4(&arg->alock, &arg4);
58974462Salfred
59074462Salfred	if (debug_level)
59174462Salfred		log_from_addr("nlm_cancel", rqstp);
59274462Salfred
59374462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
59474462Salfred	res.cookie = arg->cookie;
59574462Salfred
59674462Salfred	/*
59774462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
59874462Salfred	 * a lock to cancel, so this call always fails.
59974462Salfred	 */
60074462Salfred	res.stat.stat = unlock(&arg4, LOCK_CANCEL);
60174462Salfred	return (&res);
60274462Salfred}
60374462Salfred
60474462Salfredvoid *
60574462Salfrednlm_cancel_msg_1_svc(arg, rqstp)
60674462Salfred	nlm_cancargs *arg;
60774462Salfred	struct svc_req *rqstp;
60874462Salfred{
60974462Salfred	static nlm_res res;
61074462Salfred	struct nlm4_lock arg4;
61174462Salfred
61274462Salfred	nlmtonlm4(&arg->alock, &arg4);
61374462Salfred
61474462Salfred	if (debug_level)
61574462Salfred		log_from_addr("nlm_cancel_msg", rqstp);
61674462Salfred
61774462Salfred	res.cookie = arg->cookie;
61874462Salfred	/*
61974462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
62074462Salfred	 * a lock to cancel, so this call always fails.
62174462Salfred	 */
62274462Salfred	res.stat.stat = unlock(&arg4, LOCK_CANCEL);
623141217Skuriyama	transmit_result(NLM_CANCEL_RES, &res, getrpcaddr(rqstp));
62474462Salfred	return (NULL);
62574462Salfred}
62674462Salfred
62774462Salfred/* nlm_unlock -------------------------------------------------------------- */
62874462Salfred/*
62974462Salfred * Purpose:	Release an existing lock
63074462Salfred * Returns:	Always granted, unless during grace period
63174462Salfred * Notes:	"no such lock" error condition is ignored, as the
63274462Salfred *		protocol uses unreliable UDP datagrams, and may well
63374462Salfred *		re-try an unlock that has already succeeded.
63474462Salfred */
63574462Salfrednlm_res *
63674462Salfrednlm_unlock_1_svc(arg, rqstp)
63774462Salfred	nlm_unlockargs *arg;
63874462Salfred	struct svc_req *rqstp;
63974462Salfred{
64074462Salfred	static nlm_res res;
64174462Salfred	struct nlm4_lock arg4;
64274462Salfred
64374462Salfred	nlmtonlm4(&arg->alock, &arg4);
64474462Salfred
64574462Salfred	if (debug_level)
64674462Salfred		log_from_addr("nlm_unlock", rqstp);
64774462Salfred
64874462Salfred	res.stat.stat = unlock(&arg4, 0);
64974462Salfred	res.cookie = arg->cookie;
65074462Salfred
65174462Salfred	return (&res);
65274462Salfred}
65374462Salfred
65474462Salfredvoid *
65574462Salfrednlm_unlock_msg_1_svc(arg, rqstp)
65674462Salfred	nlm_unlockargs *arg;
65774462Salfred	struct svc_req *rqstp;
65874462Salfred{
65974462Salfred	static nlm_res res;
66074462Salfred	struct nlm4_lock arg4;
66174462Salfred
66274462Salfred	nlmtonlm4(&arg->alock, &arg4);
66374462Salfred
66474462Salfred	if (debug_level)
66574462Salfred		log_from_addr("nlm_unlock_msg", rqstp);
66674462Salfred
66774462Salfred	res.stat.stat = unlock(&arg4, 0);
66874462Salfred	res.cookie = arg->cookie;
66974462Salfred
670141217Skuriyama	transmit_result(NLM_UNLOCK_RES, &res, getrpcaddr(rqstp));
67174462Salfred	return (NULL);
67274462Salfred}
67374462Salfred
67474462Salfred/* ------------------------------------------------------------------------- */
67574462Salfred/*
67674462Salfred * Client-side pseudo-RPCs for results.  Note that for the client there
67774462Salfred * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
67874462Salfred * version returns the results in the RPC result, and so the client
67974462Salfred * does not normally receive incoming RPCs.
68074462Salfred *
68174462Salfred * The exception to this is nlm_granted(), which is genuinely an RPC
68274462Salfred * call from the server to the client - a 'call-back' in normal procedure
68374462Salfred * call terms.
68474462Salfred */
68574462Salfred
68674462Salfred/* nlm_granted ------------------------------------------------------------- */
68774462Salfred/*
68874462Salfred * Purpose:	Receive notification that formerly blocked lock now granted
68974462Salfred * Returns:	always success ('granted')
69074462Salfred * Notes:
69174462Salfred */
69274462Salfrednlm_res *
69374462Salfrednlm_granted_1_svc(arg, rqstp)
69474462Salfred	nlm_testargs *arg;
69574462Salfred	struct svc_req *rqstp;
69674462Salfred{
69774462Salfred	static nlm_res res;
69874462Salfred
69974462Salfred	if (debug_level)
70074462Salfred		log_from_addr("nlm_granted", rqstp);
70174462Salfred
70275631Salfred	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
70375631Salfred		nlm_granted, NULL, NLM_VERS) == 0 ?
70475631Salfred		nlm_granted : nlm_denied;
70575631Salfred
70674462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
70774462Salfred	res.cookie = arg->cookie;
70874462Salfred
70974462Salfred	return (&res);
71074462Salfred}
71174462Salfred
71274462Salfredvoid *
71374462Salfrednlm_granted_msg_1_svc(arg, rqstp)
71474462Salfred	nlm_testargs *arg;
71574462Salfred	struct svc_req *rqstp;
71674462Salfred{
71774462Salfred	static nlm_res res;
71874462Salfred
71974462Salfred	if (debug_level)
72074462Salfred		log_from_addr("nlm_granted_msg", rqstp);
72174462Salfred
72274462Salfred	res.cookie = arg->cookie;
723114993Srwatson	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
724114993Srwatson		nlm_granted, NULL, NLM_VERS) == 0 ?
725114993Srwatson		nlm_granted : nlm_denied;
726114993Srwatson
727141217Skuriyama	transmit_result(NLM_GRANTED_RES, &res, getrpcaddr(rqstp));
72874462Salfred	return (NULL);
72974462Salfred}
73074462Salfred
73174462Salfred/* nlm_test_res ------------------------------------------------------------ */
73274462Salfred/*
73374462Salfred * Purpose:	Accept result from earlier nlm_test_msg() call
73474462Salfred * Returns:	Nothing
73574462Salfred */
73674462Salfredvoid *
73774462Salfrednlm_test_res_1_svc(arg, rqstp)
73874462Salfred	nlm_testres *arg;
73974462Salfred	struct svc_req *rqstp;
74074462Salfred{
74174462Salfred	if (debug_level)
74274462Salfred		log_from_addr("nlm_test_res", rqstp);
74375631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat,
74475631Salfred		&arg->stat.nlm_testrply_u.holder.svid, NLM_VERS);
74574462Salfred	return (NULL);
74674462Salfred}
74774462Salfred
74874462Salfred/* nlm_lock_res ------------------------------------------------------------ */
74974462Salfred/*
75074462Salfred * Purpose:	Accept result from earlier nlm_lock_msg() call
75174462Salfred * Returns:	Nothing
75274462Salfred */
75374462Salfredvoid *
75474462Salfrednlm_lock_res_1_svc(arg, rqstp)
75574462Salfred	nlm_res *arg;
75674462Salfred	struct svc_req *rqstp;
75774462Salfred{
75874462Salfred	if (debug_level)
75974462Salfred		log_from_addr("nlm_lock_res", rqstp);
76074462Salfred
76175631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
76275631Salfred
76374462Salfred	return (NULL);
76474462Salfred}
76574462Salfred
76674462Salfred/* nlm_cancel_res ---------------------------------------------------------- */
76774462Salfred/*
76874462Salfred * Purpose:	Accept result from earlier nlm_cancel_msg() call
76974462Salfred * Returns:	Nothing
77074462Salfred */
77174462Salfredvoid *
77274462Salfrednlm_cancel_res_1_svc(arg, rqstp)
77392911Salfred	nlm_res *arg __unused;
77474462Salfred	struct svc_req *rqstp;
77574462Salfred{
77674462Salfred	if (debug_level)
77774462Salfred		log_from_addr("nlm_cancel_res", rqstp);
77874462Salfred	return (NULL);
77974462Salfred}
78074462Salfred
78174462Salfred/* nlm_unlock_res ---------------------------------------------------------- */
78274462Salfred/*
78374462Salfred * Purpose:	Accept result from earlier nlm_unlock_msg() call
78474462Salfred * Returns:	Nothing
78574462Salfred */
78674462Salfredvoid *
78774462Salfrednlm_unlock_res_1_svc(arg, rqstp)
78874462Salfred	nlm_res *arg;
78974462Salfred	struct svc_req *rqstp;
79074462Salfred{
79174462Salfred	if (debug_level)
79274462Salfred		log_from_addr("nlm_unlock_res", rqstp);
79375631Salfred
79486300Salfred	lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
79575631Salfred
79674462Salfred	return (NULL);
79774462Salfred}
79874462Salfred
79974462Salfred/* nlm_granted_res --------------------------------------------------------- */
80074462Salfred/*
80174462Salfred * Purpose:	Accept result from earlier nlm_granted_msg() call
80274462Salfred * Returns:	Nothing
80374462Salfred */
80474462Salfredvoid *
80574462Salfrednlm_granted_res_1_svc(arg, rqstp)
80692911Salfred	nlm_res *arg __unused;
80774462Salfred	struct svc_req *rqstp;
80874462Salfred{
80974462Salfred	if (debug_level)
81074462Salfred		log_from_addr("nlm_granted_res", rqstp);
81174462Salfred	return (NULL);
81274462Salfred}
81374462Salfred
81474462Salfred/* ------------------------------------------------------------------------- */
81574462Salfred/*
81674462Salfred * Calls for PCNFS locking (aka non-monitored locking, no involvement
81774462Salfred * of rpc.statd).
81874462Salfred *
81974462Salfred * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
82074462Salfred */
82174462Salfred
82274462Salfred/* nlm_share --------------------------------------------------------------- */
82374462Salfred/*
82474462Salfred * Purpose:	Establish a DOS-style lock
82574462Salfred * Returns:	success or failure
82674462Salfred * Notes:	Blocking locks are not supported - client is expected
82774462Salfred *		to retry if required.
82874462Salfred */
82974462Salfrednlm_shareres *
83074462Salfrednlm_share_3_svc(arg, rqstp)
83174462Salfred	nlm_shareargs *arg;
83274462Salfred	struct svc_req *rqstp;
83374462Salfred{
83474462Salfred	static nlm_shareres res;
83574462Salfred
83674462Salfred	if (debug_level)
83774462Salfred		log_from_addr("nlm_share", rqstp);
83874462Salfred
83974462Salfred	res.cookie = arg->cookie;
84074462Salfred	res.stat = nlm_granted;
84174462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
84274462Salfred	return (&res);
84374462Salfred}
84474462Salfred
84574462Salfred/* nlm_unshare ------------------------------------------------------------ */
84674462Salfred/*
84774462Salfred * Purpose:	Release a DOS-style lock
84874462Salfred * Returns:	nlm_granted, unless in grace period
84974462Salfred * Notes:
85074462Salfred */
85174462Salfrednlm_shareres *
85274462Salfrednlm_unshare_3_svc(arg, rqstp)
85374462Salfred	nlm_shareargs *arg;
85474462Salfred	struct svc_req *rqstp;
85574462Salfred{
85674462Salfred	static nlm_shareres res;
85774462Salfred
85874462Salfred	if (debug_level)
85974462Salfred		log_from_addr("nlm_unshare", rqstp);
86074462Salfred
86174462Salfred	res.cookie = arg->cookie;
86274462Salfred	res.stat = nlm_granted;
86374462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
86474462Salfred	return (&res);
86574462Salfred}
86674462Salfred
86774462Salfred/* nlm_nm_lock ------------------------------------------------------------ */
86874462Salfred/*
86974462Salfred * Purpose:	non-monitored version of nlm_lock()
87074462Salfred * Returns:	as for nlm_lock()
87174462Salfred * Notes:	These locks are in the same style as the standard nlm_lock,
87274462Salfred *		but the rpc.statd should not be called to establish a
87374462Salfred *		monitor for the client machine, since that machine is
87474462Salfred *		declared not to be running a rpc.statd, and so would not
87574462Salfred *		respond to the statd protocol.
87674462Salfred */
87774462Salfrednlm_res *
87874462Salfrednlm_nm_lock_3_svc(arg, rqstp)
87974462Salfred	nlm_lockargs *arg;
88074462Salfred	struct svc_req *rqstp;
88174462Salfred{
88274462Salfred	static nlm_res res;
88374462Salfred
88474462Salfred	if (debug_level)
88574462Salfred		log_from_addr("nlm_nm_lock", rqstp);
88674462Salfred
88774462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
88874462Salfred	res.cookie = arg->cookie;
88974462Salfred	res.stat.stat = nlm_granted;
89074462Salfred	return (&res);
89174462Salfred}
89274462Salfred
89374462Salfred/* nlm_free_all ------------------------------------------------------------ */
89474462Salfred/*
89574462Salfred * Purpose:	Release all locks held by a named client
89674462Salfred * Returns:	Nothing
89774462Salfred * Notes:	Potential denial of service security problem here - the
89874462Salfred *		locks to be released are specified by a host name, independent
89974462Salfred *		of the address from which the request has arrived.
90074462Salfred *		Should probably be rejected if the named host has been
90174462Salfred *		using monitored locks.
90274462Salfred */
90374462Salfredvoid *
90474462Salfrednlm_free_all_3_svc(arg, rqstp)
90592911Salfred	nlm_notify *arg __unused;
90674462Salfred	struct svc_req *rqstp;
90774462Salfred{
90874462Salfred	static char dummy;
90974462Salfred
91074462Salfred	if (debug_level)
91174462Salfred		log_from_addr("nlm_free_all", rqstp);
91274462Salfred	return (&dummy);
91374462Salfred}
91474462Salfred
91574462Salfred/* calls for nlm version 4 (NFSv3) */
91674462Salfred/* nlm_test ---------------------------------------------------------------- */
91774462Salfred/*
91874462Salfred * Purpose:	Test whether a specified lock would be granted if requested
91974462Salfred * Returns:	nlm_granted (or error code)
92074462Salfred * Notes:
92174462Salfred */
92274462Salfrednlm4_testres *
92374462Salfrednlm4_test_4_svc(arg, rqstp)
92474462Salfred	nlm4_testargs *arg;
92574462Salfred	struct svc_req *rqstp;
92674462Salfred{
92774462Salfred	static nlm4_testres res;
92874462Salfred	struct nlm4_holder *holder;
92974462Salfred
93074462Salfred	if (debug_level)
93174462Salfred		log_from_addr("nlm4_test", rqstp);
93284923Salfred	if (debug_level > 5) {
93384923Salfred		syslog(LOG_DEBUG, "Locking arguments:\n");
93484923Salfred		log_netobj(&(arg->cookie));
93584923Salfred		syslog(LOG_DEBUG, "Alock arguments:\n");
93684923Salfred		syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
93784923Salfred		syslog(LOG_DEBUG, "File Handle:\n");
93884923Salfred		log_netobj(&(arg->alock.fh));
93984923Salfred		syslog(LOG_DEBUG, "Owner Handle:\n");
94084923Salfred		log_netobj(&(arg->alock.oh));
94184923Salfred		syslog(LOG_DEBUG, "SVID:        %d\n", arg->alock.svid);
94286319Salfred		syslog(LOG_DEBUG, "Lock Offset: %llu\n",
94386319Salfred		    (unsigned long long)arg->alock.l_offset);
94486319Salfred		syslog(LOG_DEBUG, "Lock Length: %llu\n",
94586319Salfred		    (unsigned long long)arg->alock.l_len);
94684923Salfred		syslog(LOG_DEBUG, "Exclusive:   %s\n",
94784923Salfred		    (arg->exclusive ? "true" : "false"));
94884923Salfred	}
94974462Salfred
95084923Salfred	holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
95174462Salfred
95274462Salfred	/*
95374462Salfred	 * Copy the cookie from the argument into the result.  Note that this
95474462Salfred	 * is slightly hazardous, as the structure contains a pointer to a
95574462Salfred	 * malloc()ed buffer that will get freed by the caller.  However, the
95674462Salfred	 * main function transmits the result before freeing the argument
95774462Salfred	 * so it is in fact safe.
95874462Salfred	 */
95974462Salfred	res.cookie = arg->cookie;
96074462Salfred	if (holder == NULL) {
96174462Salfred		res.stat.stat = nlm4_granted;
96274462Salfred	} else {
96374462Salfred		res.stat.stat = nlm4_denied;
96474462Salfred		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
96574462Salfred		    sizeof(struct nlm4_holder));
96674462Salfred	}
96774462Salfred	return (&res);
96874462Salfred}
96974462Salfred
97074462Salfredvoid *
97174462Salfrednlm4_test_msg_4_svc(arg, rqstp)
97274462Salfred	nlm4_testargs *arg;
97374462Salfred	struct svc_req *rqstp;
97474462Salfred{
97574462Salfred	nlm4_testres res;
97674462Salfred	static char dummy;
97774462Salfred	struct sockaddr *addr;
97874462Salfred	CLIENT *cli;
97974462Salfred	int success;
98074462Salfred	struct timeval timeo;
98174462Salfred	struct nlm4_holder *holder;
98274462Salfred
98374462Salfred	if (debug_level)
98474462Salfred		log_from_addr("nlm4_test_msg", rqstp);
98574462Salfred
98684923Salfred	holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
98774462Salfred
98874462Salfred	res.cookie = arg->cookie;
98974462Salfred	if (holder == NULL) {
99074462Salfred		res.stat.stat = nlm4_granted;
99174462Salfred	} else {
99274462Salfred		res.stat.stat = nlm4_denied;
99374462Salfred		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
99474462Salfred		    sizeof(struct nlm4_holder));
99574462Salfred	}
99674462Salfred
99774462Salfred	/*
99874462Salfred	 * nlm_test has different result type to the other operations, so
99974462Salfred	 * can't use transmit4_result() in this case
100074462Salfred	 */
100174462Salfred	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
100274462Salfred	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
100374462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
100474462Salfred		timeo.tv_usec = 0;
100574462Salfred
1006121558Speter		success = clnt_call(cli, NLM4_TEST_RES,
1007121558Speter		    (xdrproc_t)xdr_nlm4_testres, &res,
1008121558Speter		    (xdrproc_t)xdr_void, &dummy, timeo);
100974462Salfred
101074462Salfred		if (debug_level > 2)
101174462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d", success);
101274462Salfred	}
101374462Salfred	return (NULL);
101474462Salfred}
101574462Salfred
101674462Salfred/* nlm_lock ---------------------------------------------------------------- */
101774462Salfred/*
101874462Salfred * Purposes:	Establish a lock
101974462Salfred * Returns:	granted, denied or blocked
102074462Salfred * Notes:	*** grace period support missing
102174462Salfred */
102274462Salfrednlm4_res *
102374462Salfrednlm4_lock_4_svc(arg, rqstp)
102474462Salfred	nlm4_lockargs *arg;
102574462Salfred	struct svc_req *rqstp;
102674462Salfred{
102774462Salfred	static nlm4_res res;
102874462Salfred
102974462Salfred	if (debug_level)
103074462Salfred		log_from_addr("nlm4_lock", rqstp);
103184923Salfred	if (debug_level > 5) {
103284923Salfred		syslog(LOG_DEBUG, "Locking arguments:\n");
103384923Salfred		log_netobj(&(arg->cookie));
103484923Salfred		syslog(LOG_DEBUG, "Alock arguments:\n");
103584923Salfred		syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
103684923Salfred		syslog(LOG_DEBUG, "File Handle:\n");
103784923Salfred		log_netobj(&(arg->alock.fh));
103884923Salfred		syslog(LOG_DEBUG, "Owner Handle:\n");
103984923Salfred		log_netobj(&(arg->alock.oh));
104084923Salfred		syslog(LOG_DEBUG, "SVID:        %d\n", arg->alock.svid);
104186319Salfred		syslog(LOG_DEBUG, "Lock Offset: %llu\n",
104286319Salfred		    (unsigned long long)arg->alock.l_offset);
104386319Salfred		syslog(LOG_DEBUG, "Lock Length: %llu\n",
104486319Salfred		    (unsigned long long)arg->alock.l_len);
104584923Salfred		syslog(LOG_DEBUG, "Block:       %s\n", (arg->block ? "true" : "false"));
104684923Salfred		syslog(LOG_DEBUG, "Exclusive:   %s\n", (arg->exclusive ? "true" : "false"));
104784923Salfred		syslog(LOG_DEBUG, "Reclaim:     %s\n", (arg->reclaim ? "true" : "false"));
104884923Salfred		syslog(LOG_DEBUG, "State num:   %d\n", arg->state);
104984923Salfred	}
105074462Salfred
105174462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_4() */
105274462Salfred	res.cookie = arg->cookie;
105374462Salfred
105474462Salfred	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_V4);
105574462Salfred	return (&res);
105674462Salfred}
105774462Salfred
105874462Salfredvoid *
105974462Salfrednlm4_lock_msg_4_svc(arg, rqstp)
106074462Salfred	nlm4_lockargs *arg;
106174462Salfred	struct svc_req *rqstp;
106274462Salfred{
106374462Salfred	static nlm4_res res;
106474462Salfred
106574462Salfred	if (debug_level)
106674462Salfred		log_from_addr("nlm4_lock_msg", rqstp);
106774462Salfred
106874462Salfred	res.cookie = arg->cookie;
106974462Salfred	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4);
1070141217Skuriyama	transmit4_result(NLM4_LOCK_RES, &res, getrpcaddr(rqstp));
107174462Salfred
107274462Salfred	return (NULL);
107374462Salfred}
107474462Salfred
107574462Salfred/* nlm_cancel -------------------------------------------------------------- */
107674462Salfred/*
107774462Salfred * Purpose:	Cancel a blocked lock request
107874462Salfred * Returns:	granted or denied
107974462Salfred * Notes:
108074462Salfred */
108174462Salfrednlm4_res *
108274462Salfrednlm4_cancel_4_svc(arg, rqstp)
108374462Salfred	nlm4_cancargs *arg;
108474462Salfred	struct svc_req *rqstp;
108574462Salfred{
108674462Salfred	static nlm4_res res;
108774462Salfred
108874462Salfred	if (debug_level)
108974462Salfred		log_from_addr("nlm4_cancel", rqstp);
109074462Salfred
109174462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
109274462Salfred	res.cookie = arg->cookie;
109374462Salfred
109474462Salfred	/*
109574462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
109674462Salfred	 * a lock to cancel, so this call always fails.
109774462Salfred	 */
109874462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL);
109974462Salfred	return (&res);
110074462Salfred}
110174462Salfred
110274462Salfredvoid *
110374462Salfrednlm4_cancel_msg_4_svc(arg, rqstp)
110474462Salfred	nlm4_cancargs *arg;
110574462Salfred	struct svc_req *rqstp;
110674462Salfred{
110774462Salfred	static nlm4_res res;
110874462Salfred
110974462Salfred	if (debug_level)
111074462Salfred		log_from_addr("nlm4_cancel_msg", rqstp);
111174462Salfred
111274462Salfred	res.cookie = arg->cookie;
111374462Salfred	/*
111474462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
111574462Salfred	 * a lock to cancel, so this call always fails.
111674462Salfred	 */
111774462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4);
1118141217Skuriyama	transmit4_result(NLM4_CANCEL_RES, &res, getrpcaddr(rqstp));
111974462Salfred	return (NULL);
112074462Salfred}
112174462Salfred
112274462Salfred/* nlm_unlock -------------------------------------------------------------- */
112374462Salfred/*
112474462Salfred * Purpose:	Release an existing lock
112574462Salfred * Returns:	Always granted, unless during grace period
112674462Salfred * Notes:	"no such lock" error condition is ignored, as the
112774462Salfred *		protocol uses unreliable UDP datagrams, and may well
112874462Salfred *		re-try an unlock that has already succeeded.
112974462Salfred */
113074462Salfrednlm4_res *
113174462Salfrednlm4_unlock_4_svc(arg, rqstp)
113274462Salfred	nlm4_unlockargs *arg;
113374462Salfred	struct svc_req *rqstp;
113474462Salfred{
113574462Salfred	static nlm4_res res;
113674462Salfred
113774462Salfred	if (debug_level)
113874462Salfred		log_from_addr("nlm4_unlock", rqstp);
113974462Salfred
114074462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_V4);
114174462Salfred	res.cookie = arg->cookie;
114274462Salfred
114374462Salfred	return (&res);
114474462Salfred}
114574462Salfred
114674462Salfredvoid *
114774462Salfrednlm4_unlock_msg_4_svc(arg, rqstp)
114874462Salfred	nlm4_unlockargs *arg;
114974462Salfred	struct svc_req *rqstp;
115074462Salfred{
115174462Salfred	static nlm4_res res;
115274462Salfred
115374462Salfred	if (debug_level)
115474462Salfred		log_from_addr("nlm4_unlock_msg", rqstp);
115574462Salfred
115674462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_V4);
115774462Salfred	res.cookie = arg->cookie;
115874462Salfred
1159141217Skuriyama	transmit4_result(NLM4_UNLOCK_RES, &res, getrpcaddr(rqstp));
116074462Salfred	return (NULL);
116174462Salfred}
116274462Salfred
116374462Salfred/* ------------------------------------------------------------------------- */
116474462Salfred/*
116574462Salfred * Client-side pseudo-RPCs for results.  Note that for the client there
116674462Salfred * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
116774462Salfred * version returns the results in the RPC result, and so the client
116874462Salfred * does not normally receive incoming RPCs.
116974462Salfred *
117074462Salfred * The exception to this is nlm_granted(), which is genuinely an RPC
117174462Salfred * call from the server to the client - a 'call-back' in normal procedure
117274462Salfred * call terms.
117374462Salfred */
117474462Salfred
117574462Salfred/* nlm_granted ------------------------------------------------------------- */
117674462Salfred/*
117774462Salfred * Purpose:	Receive notification that formerly blocked lock now granted
117874462Salfred * Returns:	always success ('granted')
117974462Salfred * Notes:
118074462Salfred */
118174462Salfrednlm4_res *
118274462Salfrednlm4_granted_4_svc(arg, rqstp)
118374462Salfred	nlm4_testargs *arg;
118474462Salfred	struct svc_req *rqstp;
118574462Salfred{
118674462Salfred	static nlm4_res res;
118774462Salfred
118874462Salfred	if (debug_level)
118974462Salfred		log_from_addr("nlm4_granted", rqstp);
119074462Salfred
119175631Salfred	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
119275631Salfred		nlm4_granted, NULL, NLM_VERS4) == 0 ?
119375631Salfred		nlm4_granted : nlm4_denied;
119475631Salfred
119574462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
119674462Salfred	res.cookie = arg->cookie;
119774462Salfred
119874462Salfred	return (&res);
119974462Salfred}
120074462Salfred
120174462Salfredvoid *
120274462Salfrednlm4_granted_msg_4_svc(arg, rqstp)
120374462Salfred	nlm4_testargs *arg;
120474462Salfred	struct svc_req *rqstp;
120574462Salfred{
120674462Salfred	static nlm4_res res;
120774462Salfred
120874462Salfred	if (debug_level)
120974462Salfred		log_from_addr("nlm4_granted_msg", rqstp);
121074462Salfred
121174462Salfred	res.cookie = arg->cookie;
1212114993Srwatson	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
1213114993Srwatson		nlm4_granted, NULL, NLM_VERS4) == 0 ?
1214114993Srwatson		nlm4_granted : nlm4_denied;
1215141217Skuriyama	transmit4_result(NLM4_GRANTED_RES, &res, getrpcaddr(rqstp));
121674462Salfred	return (NULL);
121774462Salfred}
121874462Salfred
121974462Salfred/* nlm_test_res ------------------------------------------------------------ */
122074462Salfred/*
122174462Salfred * Purpose:	Accept result from earlier nlm_test_msg() call
122274462Salfred * Returns:	Nothing
122374462Salfred */
122474462Salfredvoid *
122574462Salfrednlm4_test_res_4_svc(arg, rqstp)
122674462Salfred	nlm4_testres *arg;
122774462Salfred	struct svc_req *rqstp;
122874462Salfred{
122974462Salfred	if (debug_level)
123074462Salfred		log_from_addr("nlm4_test_res", rqstp);
123175631Salfred
123275631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat,
123375631Salfred		(int *)&arg->stat.nlm4_testrply_u.holder.svid,
123475631Salfred		NLM_VERS4);
123574462Salfred	return (NULL);
123674462Salfred}
123774462Salfred
123874462Salfred/* nlm_lock_res ------------------------------------------------------------ */
123974462Salfred/*
124074462Salfred * Purpose:	Accept result from earlier nlm_lock_msg() call
124174462Salfred * Returns:	Nothing
124274462Salfred */
124374462Salfredvoid *
124474462Salfrednlm4_lock_res_4_svc(arg, rqstp)
124574462Salfred	nlm4_res *arg;
124674462Salfred	struct svc_req *rqstp;
124774462Salfred{
124874462Salfred	if (debug_level)
124974462Salfred		log_from_addr("nlm4_lock_res", rqstp);
125074462Salfred
125175631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS4);
125275631Salfred
125374462Salfred	return (NULL);
125474462Salfred}
125574462Salfred
125674462Salfred/* nlm_cancel_res ---------------------------------------------------------- */
125774462Salfred/*
125874462Salfred * Purpose:	Accept result from earlier nlm_cancel_msg() call
125974462Salfred * Returns:	Nothing
126074462Salfred */
126174462Salfredvoid *
126274462Salfrednlm4_cancel_res_4_svc(arg, rqstp)
126392911Salfred	nlm4_res *arg __unused;
126474462Salfred	struct svc_req *rqstp;
126574462Salfred{
126674462Salfred	if (debug_level)
126774462Salfred		log_from_addr("nlm4_cancel_res", rqstp);
126874462Salfred	return (NULL);
126974462Salfred}
127074462Salfred
127174462Salfred/* nlm_unlock_res ---------------------------------------------------------- */
127274462Salfred/*
127374462Salfred * Purpose:	Accept result from earlier nlm_unlock_msg() call
127474462Salfred * Returns:	Nothing
127574462Salfred */
127674462Salfredvoid *
127774462Salfrednlm4_unlock_res_4_svc(arg, rqstp)
127892911Salfred	nlm4_res *arg __unused;
127974462Salfred	struct svc_req *rqstp;
128074462Salfred{
128174462Salfred	if (debug_level)
128274462Salfred		log_from_addr("nlm4_unlock_res", rqstp);
128374462Salfred	return (NULL);
128474462Salfred}
128574462Salfred
128674462Salfred/* nlm_granted_res --------------------------------------------------------- */
128774462Salfred/*
128874462Salfred * Purpose:	Accept result from earlier nlm_granted_msg() call
128974462Salfred * Returns:	Nothing
129074462Salfred */
129174462Salfredvoid *
129274462Salfrednlm4_granted_res_4_svc(arg, rqstp)
129392911Salfred	nlm4_res *arg __unused;
129474462Salfred	struct svc_req *rqstp;
129574462Salfred{
129674462Salfred	if (debug_level)
129774462Salfred		log_from_addr("nlm4_granted_res", rqstp);
129874462Salfred	return (NULL);
129974462Salfred}
130074462Salfred
130174462Salfred/* ------------------------------------------------------------------------- */
130274462Salfred/*
130374462Salfred * Calls for PCNFS locking (aka non-monitored locking, no involvement
130474462Salfred * of rpc.statd).
130574462Salfred *
130674462Salfred * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
130774462Salfred */
130874462Salfred
130974462Salfred/* nlm_share --------------------------------------------------------------- */
131074462Salfred/*
131174462Salfred * Purpose:	Establish a DOS-style lock
131274462Salfred * Returns:	success or failure
131374462Salfred * Notes:	Blocking locks are not supported - client is expected
131474462Salfred *		to retry if required.
131574462Salfred */
131674462Salfrednlm4_shareres *
131774462Salfrednlm4_share_4_svc(arg, rqstp)
131874462Salfred	nlm4_shareargs *arg;
131974462Salfred	struct svc_req *rqstp;
132074462Salfred{
132174462Salfred	static nlm4_shareres res;
132274462Salfred
132374462Salfred	if (debug_level)
132474462Salfred		log_from_addr("nlm4_share", rqstp);
132574462Salfred
132674462Salfred	res.cookie = arg->cookie;
132774462Salfred	res.stat = nlm4_granted;
132874462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
132974462Salfred	return (&res);
133074462Salfred}
133174462Salfred
133274462Salfred/* nlm4_unshare ------------------------------------------------------------ */
133374462Salfred/*
133474462Salfred * Purpose:	Release a DOS-style lock
133574462Salfred * Returns:	nlm_granted, unless in grace period
133674462Salfred * Notes:
133774462Salfred */
133874462Salfrednlm4_shareres *
133974462Salfrednlm4_unshare_4_svc(arg, rqstp)
134074462Salfred	nlm4_shareargs *arg;
134174462Salfred	struct svc_req *rqstp;
134274462Salfred{
134374462Salfred	static nlm4_shareres res;
134474462Salfred
134574462Salfred	if (debug_level)
134674462Salfred		log_from_addr("nlm_unshare", rqstp);
134774462Salfred
134874462Salfred	res.cookie = arg->cookie;
134974462Salfred	res.stat = nlm4_granted;
135074462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
135174462Salfred	return (&res);
135274462Salfred}
135374462Salfred
135474462Salfred/* nlm4_nm_lock ------------------------------------------------------------ */
135574462Salfred/*
135674462Salfred * Purpose:	non-monitored version of nlm4_lock()
135774462Salfred * Returns:	as for nlm4_lock()
135874462Salfred * Notes:	These locks are in the same style as the standard nlm4_lock,
135974462Salfred *		but the rpc.statd should not be called to establish a
136074462Salfred *		monitor for the client machine, since that machine is
136174462Salfred *		declared not to be running a rpc.statd, and so would not
136274462Salfred *		respond to the statd protocol.
136374462Salfred */
136474462Salfrednlm4_res *
136574462Salfrednlm4_nm_lock_4_svc(arg, rqstp)
136674462Salfred	nlm4_lockargs *arg;
136774462Salfred	struct svc_req *rqstp;
136874462Salfred{
136974462Salfred	static nlm4_res res;
137074462Salfred
137174462Salfred	if (debug_level)
137274462Salfred		log_from_addr("nlm4_nm_lock", rqstp);
137374462Salfred
137474462Salfred	/* copy cookie from arg to result.  See comment in nlm4_test_1() */
137574462Salfred	res.cookie = arg->cookie;
137674462Salfred	res.stat.stat = nlm4_granted;
137774462Salfred	return (&res);
137874462Salfred}
137974462Salfred
138074462Salfred/* nlm4_free_all ------------------------------------------------------------ */
138174462Salfred/*
138274462Salfred * Purpose:	Release all locks held by a named client
138374462Salfred * Returns:	Nothing
138474462Salfred * Notes:	Potential denial of service security problem here - the
138574462Salfred *		locks to be released are specified by a host name, independent
138674462Salfred *		of the address from which the request has arrived.
138774462Salfred *		Should probably be rejected if the named host has been
138874462Salfred *		using monitored locks.
138974462Salfred */
139074462Salfredvoid *
139174462Salfrednlm4_free_all_4_svc(arg, rqstp)
139292911Salfred	struct nlm4_notify *arg __unused;
139374462Salfred	struct svc_req *rqstp;
139474462Salfred{
139574462Salfred	static char dummy;
139674462Salfred
139774462Salfred	if (debug_level)
139874462Salfred		log_from_addr("nlm4_free_all", rqstp);
139974462Salfred	return (&dummy);
140074462Salfred}
140174462Salfred
140274462Salfred/* nlm_sm_notify --------------------------------------------------------- */
140374462Salfred/*
140474462Salfred * Purpose:	called by rpc.statd when a monitored host state changes.
140574462Salfred * Returns:	Nothing
140674462Salfred */
140774462Salfredvoid *
140874462Salfrednlm_sm_notify_0_svc(arg, rqstp)
140974462Salfred	struct nlm_sm_status *arg;
141092911Salfred	struct svc_req *rqstp __unused;
141174462Salfred{
141274462Salfred	static char dummy;
141374462Salfred	notify(arg->mon_name, arg->state);
141474462Salfred	return (&dummy);
141574462Salfred}
1416