lock_proc.c revision 114993
174462Salfred/*	$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $	*/
274462Salfred/*	$FreeBSD: head/usr.sbin/rpc.lockd/lock_proc.c 114993 2003-05-14 13:50:40Z rwatson $ */
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>
5174462Salfred#include <netconfig.h>
5274462Salfred
5374462Salfred#include <rpc/rpc.h>
5474462Salfred#include <rpcsvc/sm_inter.h>
5574462Salfred
5674462Salfred#include "lockd.h"
5774462Salfred#include <rpcsvc/nlm_prot.h>
5874462Salfred#include "lockd_lock.h"
5974462Salfred
6074462Salfred
6174462Salfred#define	CLIENT_CACHE_SIZE	64	/* No. of client sockets cached */
6274462Salfred#define	CLIENT_CACHE_LIFETIME	120	/* In seconds */
6374462Salfred
6492969Salfredstatic void	log_from_addr(const char *, struct svc_req *);
6592909Salfredstatic void	log_netobj(netobj *obj);
6692909Salfredstatic int	addrcmp(struct sockaddr *, struct sockaddr *);
6774462Salfred
6874462Salfred/* log_from_addr ----------------------------------------------------------- */
6974462Salfred/*
7074462Salfred * Purpose:	Log name of function called and source address
7174462Salfred * Returns:	Nothing
7274462Salfred * Notes:	Extracts the source address from the transport handle
7374462Salfred *		passed in as part of the called procedure specification
7474462Salfred */
7574462Salfredstatic void
7674462Salfredlog_from_addr(fun_name, req)
7792969Salfred	const char *fun_name;
7874462Salfred	struct svc_req *req;
7974462Salfred{
8074462Salfred	struct sockaddr *addr;
8174462Salfred	char hostname_buf[NI_MAXHOST];
8274462Salfred
8374462Salfred	addr = svc_getrpccaller(req->rq_xprt)->buf;
8474462Salfred	if (getnameinfo(addr , addr->sa_len, hostname_buf, sizeof hostname_buf,
8574462Salfred	    NULL, 0, 0) != 0)
8674462Salfred		return;
8774462Salfred
8874462Salfred	syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
8974462Salfred}
9074462Salfred
9184923Salfred/* log_netobj ----------------------------------------------------------- */
9284923Salfred/*
9384923Salfred * Purpose:	Log a netobj
9484923Salfred * Returns:	Nothing
9584923Salfred * Notes:	This function should only really be called as part of
9684923Salfred *  		a debug subsystem.
9784923Salfred*/
9884923Salfredstatic void
9984923Salfredlog_netobj(obj)
10084923Salfred	netobj *obj;
10184923Salfred{
10284923Salfred	char objvalbuffer[(sizeof(char)*2)*MAX_NETOBJ_SZ+2];
10384923Salfred	char objascbuffer[sizeof(char)*MAX_NETOBJ_SZ+1];
10486319Salfred	unsigned int i, maxlen;
10584923Salfred	char *tmp1, *tmp2;
10684923Salfred
10784923Salfred	/* Notify of potential security attacks */
10884923Salfred	if (obj->n_len > MAX_NETOBJ_SZ)	{
10984923Salfred		syslog(LOG_DEBUG, "SOMEONE IS TRYING TO DO SOMETHING NASTY!\n");
11084923Salfred		syslog(LOG_DEBUG, "netobj too large! Should be %d was %d\n",
11184923Salfred		    MAX_NETOBJ_SZ, obj->n_len);
11284923Salfred	}
11384923Salfred	/* Prevent the security hazard from the buffer overflow */
11484923Salfred	maxlen = (obj->n_len < MAX_NETOBJ_SZ ? obj->n_len : MAX_NETOBJ_SZ);
11584923Salfred	for (i=0, tmp1 = objvalbuffer, tmp2 = objascbuffer; i < obj->n_len;
11684923Salfred	    i++, tmp1 +=2, tmp2 +=1) {
11784923Salfred		sprintf(tmp1,"%02X",*(obj->n_bytes+i));
11884923Salfred		sprintf(tmp2,"%c",*(obj->n_bytes+i));
11984923Salfred	}
12084923Salfred	*tmp1 = '\0';
12184923Salfred	*tmp2 = '\0';
12284923Salfred	syslog(LOG_DEBUG,"netobjvals: %s\n",objvalbuffer);
12384923Salfred	syslog(LOG_DEBUG,"netobjascs: %s\n",objascbuffer);
12484923Salfred}
12574462Salfred/* get_client -------------------------------------------------------------- */
12674462Salfred/*
12774462Salfred * Purpose:	Get a CLIENT* for making RPC calls to lockd on given host
12874462Salfred * Returns:	CLIENT* pointer, from clnt_udp_create, or NULL if error
12974462Salfred * Notes:	Creating a CLIENT* is quite expensive, involving a
13074462Salfred *		conversation with the remote portmapper to get the
13174462Salfred *		port number.  Since a given client is quite likely
13274462Salfred *		to make several locking requests in succession, it is
13374462Salfred *		desirable to cache the created CLIENT*.
13474462Salfred *
13574462Salfred *		Since we are using UDP rather than TCP, there is no cost
13674462Salfred *		to the remote system in keeping these cached indefinitely.
13774462Salfred *		Unfortunately there is a snag: if the remote system
13874462Salfred *		reboots, the cached portmapper results will be invalid,
13974462Salfred *		and we will never detect this since all of the xxx_msg()
14074462Salfred *		calls return no result - we just fire off a udp packet
14174462Salfred *		and hope for the best.
14274462Salfred *
14374462Salfred *		We solve this by discarding cached values after two
14474462Salfred *		minutes, regardless of whether they have been used
14574462Salfred *		in the meanwhile (since a bad one might have been used
14674462Salfred *		plenty of times, as the host keeps retrying the request
14774462Salfred *		and we keep sending the reply back to the wrong port).
14874462Salfred *
14974462Salfred *		Given that the entries will always expire in the order
15074462Salfred *		that they were created, there is no point in a LRU
15174462Salfred *		algorithm for when the cache gets full - entries are
15274462Salfred *		always re-used in sequence.
15374462Salfred */
15474462Salfredstatic CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
15574462Salfredstatic long clnt_cache_time[CLIENT_CACHE_SIZE];	/* time entry created */
15674462Salfredstatic struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE];
15776093Salfredstatic rpcvers_t clnt_cache_vers[CLIENT_CACHE_SIZE];
15874462Salfredstatic int clnt_cache_next_to_use = 0;
15974462Salfred
16074462Salfredstatic int
16174462Salfredaddrcmp(sa1, sa2)
16274462Salfred	struct sockaddr *sa1;
16374462Salfred	struct sockaddr *sa2;
16474462Salfred{
16574462Salfred	int len;
16674462Salfred	void *p1, *p2;
16774462Salfred
16874462Salfred	if (sa1->sa_family != sa2->sa_family)
16974462Salfred		return -1;
17074462Salfred
17174462Salfred	switch (sa1->sa_family) {
17274462Salfred	case AF_INET:
17374462Salfred		p1 = &((struct sockaddr_in *)sa1)->sin_addr;
17474462Salfred		p2 = &((struct sockaddr_in *)sa2)->sin_addr;
17574462Salfred		len = 4;
17674462Salfred		break;
17774462Salfred	case AF_INET6:
17874462Salfred		p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
17974462Salfred		p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
18074462Salfred		len = 16;
18174462Salfred		break;
18274462Salfred	default:
18374462Salfred		return -1;
18474462Salfred	}
18574462Salfred
18674462Salfred	return memcmp(p1, p2, len);
18774462Salfred}
18874462Salfred
18974462SalfredCLIENT *
19074462Salfredget_client(host_addr, vers)
19174462Salfred	struct sockaddr *host_addr;
19274462Salfred	rpcvers_t vers;
19374462Salfred{
19474462Salfred	CLIENT *client;
19574462Salfred	struct timeval retry_time, time_now;
19674462Salfred	int i;
19792977Salfred	const char *netid;
19874462Salfred	struct netconfig *nconf;
19974462Salfred	char host[NI_MAXHOST];
20074462Salfred
20174462Salfred	gettimeofday(&time_now, NULL);
20274462Salfred
20374462Salfred	/*
20474462Salfred	 * Search for the given client in the cache, zapping any expired
20574462Salfred	 * entries that we happen to notice in passing.
20674462Salfred	 */
20774462Salfred	for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
20874462Salfred		client = clnt_cache_ptr[i];
20974462Salfred		if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
21074462Salfred		    < time_now.tv_sec)) {
21174462Salfred			/* Cache entry has expired. */
21274462Salfred			if (debug_level > 3)
21374462Salfred				syslog(LOG_DEBUG, "Expired CLIENT* in cache");
21474462Salfred			clnt_cache_time[i] = 0L;
21574462Salfred			clnt_destroy(client);
21674462Salfred			clnt_cache_ptr[i] = NULL;
21774462Salfred			client = NULL;
21874462Salfred		}
21974462Salfred		if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i],
22076093Salfred		    host_addr) && clnt_cache_vers[i] == vers) {
22174462Salfred			/* Found it! */
22274462Salfred			if (debug_level > 3)
22374462Salfred				syslog(LOG_DEBUG, "Found CLIENT* in cache");
22474462Salfred			return (client);
22574462Salfred		}
22674462Salfred	}
22774462Salfred
22876093Salfred	if (debug_level > 3)
22976093Salfred		syslog(LOG_DEBUG, "CLIENT* not found in cache, creating");
23076093Salfred
23174462Salfred	/* Not found in cache.  Free the next entry if it is in use. */
23274462Salfred	if (clnt_cache_ptr[clnt_cache_next_to_use]) {
23374462Salfred		clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
23474462Salfred		clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
23574462Salfred	}
23674462Salfred
23774462Salfred	/*
23874462Salfred	 * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
23974462Salfred	 * to avoid DNS lookups.
24074462Salfred	 */
24174462Salfred	if (getnameinfo(host_addr, host_addr->sa_len, host, sizeof host,
24274462Salfred	    NULL, 0, NI_NUMERICHOST) != 0) {
24374462Salfred		syslog(LOG_ERR, "unable to get name string for caller");
24474462Salfred		return NULL;
24574462Salfred	}
24674462Salfred
24774462Salfred#if 1
24874462Salfred	if (host_addr->sa_family == AF_INET6)
24974462Salfred		netid = "udp6";
25074462Salfred	else
25174462Salfred		netid = "udp";
25274462Salfred#else
25374462Salfred	if (host_addr->sa_family == AF_INET6)
25474462Salfred		netid = "tcp6";
25574462Salfred	else
25674462Salfred		netid = "tcp";
25774462Salfred#endif
25874462Salfred	nconf = getnetconfigent(netid);
25974462Salfred	if (nconf == NULL) {
26074462Salfred		syslog(LOG_ERR, "could not get netconfig info for '%s': "
26174462Salfred				"no /etc/netconfig file?", netid);
26274462Salfred		return NULL;
26374462Salfred	}
26474462Salfred
26574462Salfred	client = clnt_tp_create(host, NLM_PROG, vers, nconf);
26674462Salfred	freenetconfigent(nconf);
26774462Salfred
26874462Salfred	if (!client) {
26974462Salfred		syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create"));
27074462Salfred		syslog(LOG_ERR, "Unable to return result to %s", host);
27174462Salfred		return NULL;
27274462Salfred	}
27374462Salfred
27474462Salfred	/* Success - update the cache entry */
27574462Salfred	clnt_cache_ptr[clnt_cache_next_to_use] = client;
27674462Salfred	memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
27774462Salfred	    host_addr->sa_len);
27876093Salfred	clnt_cache_vers[clnt_cache_next_to_use] = vers;
27974462Salfred	clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
28074462Salfred	if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE)
28174462Salfred		clnt_cache_next_to_use = 0;
28274462Salfred
28374462Salfred	/*
28474462Salfred	 * Disable the default timeout, so we can specify our own in calls
28574462Salfred	 * to clnt_call().  (Note that the timeout is a different concept
28674462Salfred	 * from the retry period set in clnt_udp_create() above.)
28774462Salfred	 */
28874462Salfred	retry_time.tv_sec = -1;
28974462Salfred	retry_time.tv_usec = -1;
29074462Salfred	clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
29174462Salfred
29274462Salfred	if (debug_level > 3)
29374462Salfred		syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
29474462Salfred	return client;
29574462Salfred}
29674462Salfred
29774462Salfred
29874462Salfred/* transmit_result --------------------------------------------------------- */
29974462Salfred/*
30074462Salfred * Purpose:	Transmit result for nlm_xxx_msg pseudo-RPCs
30174462Salfred * Returns:	Nothing - we have no idea if the datagram got there
30274462Salfred * Notes:	clnt_call() will always fail (with timeout) as we are
30374462Salfred *		calling it with timeout 0 as a hack to just issue a datagram
30474462Salfred *		without expecting a result
30574462Salfred */
30674462Salfredvoid
30774462Salfredtransmit_result(opcode, result, addr)
30874462Salfred	int opcode;
30974462Salfred	nlm_res *result;
31074462Salfred	struct sockaddr *addr;
31174462Salfred{
31274462Salfred	static char dummy;
31374462Salfred	CLIENT *cli;
31474462Salfred	struct timeval timeo;
31574462Salfred	int success;
31674462Salfred
31774462Salfred	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
31874462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
31974462Salfred		timeo.tv_usec = 0;
32074462Salfred
32174462Salfred		success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void,
32274462Salfred		    &dummy, timeo);
32374462Salfred
32474462Salfred		if (debug_level > 2)
32574462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
32674462Salfred			    success, clnt_sperrno(success));
32774462Salfred	}
32874462Salfred}
32974462Salfred/* transmit4_result --------------------------------------------------------- */
33074462Salfred/*
33174462Salfred * Purpose:	Transmit result for nlm4_xxx_msg pseudo-RPCs
33274462Salfred * Returns:	Nothing - we have no idea if the datagram got there
33374462Salfred * Notes:	clnt_call() will always fail (with timeout) as we are
33474462Salfred *		calling it with timeout 0 as a hack to just issue a datagram
33574462Salfred *		without expecting a result
33674462Salfred */
33774462Salfredvoid
33874462Salfredtransmit4_result(opcode, result, addr)
33974462Salfred	int opcode;
34074462Salfred	nlm4_res *result;
34174462Salfred	struct sockaddr *addr;
34274462Salfred{
34374462Salfred	static char dummy;
34474462Salfred	CLIENT *cli;
34574462Salfred	struct timeval timeo;
34674462Salfred	int success;
34774462Salfred
34874462Salfred	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
34974462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
35074462Salfred		timeo.tv_usec = 0;
35174462Salfred
35274462Salfred		success = clnt_call(cli, opcode, xdr_nlm4_res, result, xdr_void,
35374462Salfred		    &dummy, timeo);
35474462Salfred
35574462Salfred		if (debug_level > 2)
35674462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
35774462Salfred			    success, clnt_sperrno(success));
35874462Salfred	}
35974462Salfred}
36074462Salfred
36174462Salfred/*
36274462Salfred * converts a struct nlm_lock to struct nlm4_lock
36374462Salfred */
36492909Salfredstatic void nlmtonlm4(struct nlm_lock *, struct nlm4_lock *);
36574462Salfredstatic void
36674462Salfrednlmtonlm4(arg, arg4)
36774462Salfred	struct nlm_lock *arg;
36874462Salfred	struct nlm4_lock *arg4;
36974462Salfred{
37074462Salfred	memcpy(arg4, arg, sizeof(nlm_lock));
37174462Salfred	arg4->l_offset = arg->l_offset;
37274462Salfred	arg4->l_len = arg->l_len;
37374462Salfred}
37474462Salfred/* ------------------------------------------------------------------------- */
37574462Salfred/*
37674462Salfred * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
37774462Salfred * involved to ensure reclaim of locks after a crash of the "stateless"
37874462Salfred * server.
37974462Salfred *
38074462Salfred * These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
38174462Salfred * The first are standard RPCs with argument and result.
38274462Salfred * The nlm_xxx_msg() calls implement exactly the same functions, but
38374462Salfred * use two pseudo-RPCs (one in each direction).  These calls are NOT
38474462Salfred * standard use of the RPC protocol in that they do not return a result
38574462Salfred * at all (NB. this is quite different from returning a void result).
38674462Salfred * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
38774462Salfred * datagrams, requiring higher-level code to perform retries.
38874462Salfred *
38974462Salfred * Despite the disadvantages of the nlm_xxx_msg() approach (some of which
39074462Salfred * are documented in the comments to get_client() above), this is the
39174462Salfred * interface used by all current commercial NFS implementations
39274462Salfred * [Solaris, SCO, AIX etc.].  This is presumed to be because these allow
39374462Salfred * implementations to continue using the standard RPC libraries, while
39474462Salfred * avoiding the block-until-result nature of the library interface.
39574462Salfred *
39674462Salfred * No client implementations have been identified so far that make use
39774462Salfred * of the true RPC version (early SunOS releases would be a likely candidate
39874462Salfred * for testing).
39974462Salfred */
40074462Salfred
40174462Salfred/* nlm_test ---------------------------------------------------------------- */
40274462Salfred/*
40374462Salfred * Purpose:	Test whether a specified lock would be granted if requested
40474462Salfred * Returns:	nlm_granted (or error code)
40574462Salfred * Notes:
40674462Salfred */
40774462Salfrednlm_testres *
40874462Salfrednlm_test_1_svc(arg, rqstp)
40974462Salfred	nlm_testargs *arg;
41074462Salfred	struct svc_req *rqstp;
41174462Salfred{
41274462Salfred	static nlm_testres res;
41374462Salfred	struct nlm4_lock arg4;
41474462Salfred	struct nlm4_holder *holder;
41574462Salfred	nlmtonlm4(&arg->alock, &arg4);
41674462Salfred
41774462Salfred	if (debug_level)
41874462Salfred		log_from_addr("nlm_test", rqstp);
41974462Salfred
42084923Salfred	holder = testlock(&arg4, arg->exclusive, 0);
42174462Salfred	/*
42274462Salfred	 * Copy the cookie from the argument into the result.  Note that this
42374462Salfred	 * is slightly hazardous, as the structure contains a pointer to a
42474462Salfred	 * malloc()ed buffer that will get freed by the caller.  However, the
42574462Salfred	 * main function transmits the result before freeing the argument
42674462Salfred	 * so it is in fact safe.
42774462Salfred	 */
42874462Salfred	res.cookie = arg->cookie;
42974462Salfred	if (holder == NULL) {
43074462Salfred		res.stat.stat = nlm_granted;
43174462Salfred	} else {
43274462Salfred		res.stat.stat = nlm_denied;
43374462Salfred		memcpy(&res.stat.nlm_testrply_u.holder, holder,
43474462Salfred		    sizeof(struct nlm_holder));
43574462Salfred		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
43674462Salfred		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
43774462Salfred	}
43874462Salfred	return (&res);
43974462Salfred}
44074462Salfred
44174462Salfredvoid *
44274462Salfrednlm_test_msg_1_svc(arg, rqstp)
44374462Salfred	nlm_testargs *arg;
44474462Salfred	struct svc_req *rqstp;
44574462Salfred{
44674462Salfred	nlm_testres res;
44774462Salfred	static char dummy;
44874462Salfred	struct sockaddr *addr;
44974462Salfred	CLIENT *cli;
45074462Salfred	int success;
45174462Salfred	struct timeval timeo;
45274462Salfred	struct nlm4_lock arg4;
45374462Salfred	struct nlm4_holder *holder;
45474462Salfred
45574462Salfred	nlmtonlm4(&arg->alock, &arg4);
45674462Salfred
45774462Salfred	if (debug_level)
45874462Salfred		log_from_addr("nlm_test_msg", rqstp);
45974462Salfred
46084923Salfred	holder = testlock(&arg4, arg->exclusive, 0);
46174462Salfred
46274462Salfred	res.cookie = arg->cookie;
46374462Salfred	if (holder == NULL) {
46474462Salfred		res.stat.stat = nlm_granted;
46574462Salfred	} else {
46674462Salfred		res.stat.stat = nlm_denied;
46774462Salfred		memcpy(&res.stat.nlm_testrply_u.holder, holder,
46874462Salfred		    sizeof(struct nlm_holder));
46974462Salfred		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
47074462Salfred		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
47174462Salfred	}
47274462Salfred
47374462Salfred	/*
47474462Salfred	 * nlm_test has different result type to the other operations, so
47574462Salfred	 * can't use transmit_result() in this case
47674462Salfred	 */
47774462Salfred	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
47874462Salfred	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
47974462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
48074462Salfred		timeo.tv_usec = 0;
48174462Salfred
48274462Salfred		success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres,
48374462Salfred		    &res, xdr_void, &dummy, timeo);
48474462Salfred
48574462Salfred		if (debug_level > 2)
48674462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d", success);
48774462Salfred	}
48874462Salfred	return (NULL);
48974462Salfred}
49074462Salfred
49174462Salfred/* nlm_lock ---------------------------------------------------------------- */
49274462Salfred/*
49374462Salfred * Purposes:	Establish a lock
49474462Salfred * Returns:	granted, denied or blocked
49574462Salfred * Notes:	*** grace period support missing
49674462Salfred */
49774462Salfrednlm_res *
49874462Salfrednlm_lock_1_svc(arg, rqstp)
49974462Salfred	nlm_lockargs *arg;
50074462Salfred	struct svc_req *rqstp;
50174462Salfred{
50274462Salfred	static nlm_res res;
50374462Salfred	struct nlm4_lockargs arg4;
50474462Salfred	nlmtonlm4(&arg->alock, &arg4.alock);
50574462Salfred	arg4.cookie = arg->cookie;
50674462Salfred	arg4.block = arg->block;
50774462Salfred	arg4.exclusive = arg->exclusive;
50874462Salfred	arg4.reclaim = arg->reclaim;
50974462Salfred	arg4.state = arg->state;
51074462Salfred
51174462Salfred	if (debug_level)
51274462Salfred		log_from_addr("nlm_lock", rqstp);
51374462Salfred
51474462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
51574462Salfred	res.cookie = arg->cookie;
51674462Salfred
51774462Salfred	res.stat.stat = getlock(&arg4, rqstp, LOCK_MON);
51874462Salfred	return (&res);
51974462Salfred}
52074462Salfred
52174462Salfredvoid *
52274462Salfrednlm_lock_msg_1_svc(arg, rqstp)
52374462Salfred	nlm_lockargs *arg;
52474462Salfred	struct svc_req *rqstp;
52574462Salfred{
52674462Salfred	static nlm_res res;
52774462Salfred	struct nlm4_lockargs arg4;
52874462Salfred
52974462Salfred	nlmtonlm4(&arg->alock, &arg4.alock);
53074462Salfred	arg4.cookie = arg->cookie;
53174462Salfred	arg4.block = arg->block;
53274462Salfred	arg4.exclusive = arg->exclusive;
53374462Salfred	arg4.reclaim = arg->reclaim;
53474462Salfred	arg4.state = arg->state;
53574462Salfred
53674462Salfred	if (debug_level)
53774462Salfred		log_from_addr("nlm_lock_msg", rqstp);
53874462Salfred
53974462Salfred	res.cookie = arg->cookie;
54074462Salfred	res.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON);
54174462Salfred	transmit_result(NLM_LOCK_RES, &res,
54274462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
54374462Salfred
54474462Salfred	return (NULL);
54574462Salfred}
54674462Salfred
54774462Salfred/* nlm_cancel -------------------------------------------------------------- */
54874462Salfred/*
54974462Salfred * Purpose:	Cancel a blocked lock request
55074462Salfred * Returns:	granted or denied
55174462Salfred * Notes:
55274462Salfred */
55374462Salfrednlm_res *
55474462Salfrednlm_cancel_1_svc(arg, rqstp)
55574462Salfred	nlm_cancargs *arg;
55674462Salfred	struct svc_req *rqstp;
55774462Salfred{
55874462Salfred	static nlm_res res;
55974462Salfred	struct nlm4_lock arg4;
56074462Salfred
56174462Salfred	nlmtonlm4(&arg->alock, &arg4);
56274462Salfred
56374462Salfred	if (debug_level)
56474462Salfred		log_from_addr("nlm_cancel", rqstp);
56574462Salfred
56674462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
56774462Salfred	res.cookie = arg->cookie;
56874462Salfred
56974462Salfred	/*
57074462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
57174462Salfred	 * a lock to cancel, so this call always fails.
57274462Salfred	 */
57374462Salfred	res.stat.stat = unlock(&arg4, LOCK_CANCEL);
57474462Salfred	return (&res);
57574462Salfred}
57674462Salfred
57774462Salfredvoid *
57874462Salfrednlm_cancel_msg_1_svc(arg, rqstp)
57974462Salfred	nlm_cancargs *arg;
58074462Salfred	struct svc_req *rqstp;
58174462Salfred{
58274462Salfred	static nlm_res res;
58374462Salfred	struct nlm4_lock arg4;
58474462Salfred
58574462Salfred	nlmtonlm4(&arg->alock, &arg4);
58674462Salfred
58774462Salfred	if (debug_level)
58874462Salfred		log_from_addr("nlm_cancel_msg", rqstp);
58974462Salfred
59074462Salfred	res.cookie = arg->cookie;
59174462Salfred	/*
59274462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
59374462Salfred	 * a lock to cancel, so this call always fails.
59474462Salfred	 */
59574462Salfred	res.stat.stat = unlock(&arg4, LOCK_CANCEL);
59674462Salfred	transmit_result(NLM_CANCEL_RES, &res,
59774462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
59874462Salfred	return (NULL);
59974462Salfred}
60074462Salfred
60174462Salfred/* nlm_unlock -------------------------------------------------------------- */
60274462Salfred/*
60374462Salfred * Purpose:	Release an existing lock
60474462Salfred * Returns:	Always granted, unless during grace period
60574462Salfred * Notes:	"no such lock" error condition is ignored, as the
60674462Salfred *		protocol uses unreliable UDP datagrams, and may well
60774462Salfred *		re-try an unlock that has already succeeded.
60874462Salfred */
60974462Salfrednlm_res *
61074462Salfrednlm_unlock_1_svc(arg, rqstp)
61174462Salfred	nlm_unlockargs *arg;
61274462Salfred	struct svc_req *rqstp;
61374462Salfred{
61474462Salfred	static nlm_res res;
61574462Salfred	struct nlm4_lock arg4;
61674462Salfred
61774462Salfred	nlmtonlm4(&arg->alock, &arg4);
61874462Salfred
61974462Salfred	if (debug_level)
62074462Salfred		log_from_addr("nlm_unlock", rqstp);
62174462Salfred
62274462Salfred	res.stat.stat = unlock(&arg4, 0);
62374462Salfred	res.cookie = arg->cookie;
62474462Salfred
62574462Salfred	return (&res);
62674462Salfred}
62774462Salfred
62874462Salfredvoid *
62974462Salfrednlm_unlock_msg_1_svc(arg, rqstp)
63074462Salfred	nlm_unlockargs *arg;
63174462Salfred	struct svc_req *rqstp;
63274462Salfred{
63374462Salfred	static nlm_res res;
63474462Salfred	struct nlm4_lock arg4;
63574462Salfred
63674462Salfred	nlmtonlm4(&arg->alock, &arg4);
63774462Salfred
63874462Salfred	if (debug_level)
63974462Salfred		log_from_addr("nlm_unlock_msg", rqstp);
64074462Salfred
64174462Salfred	res.stat.stat = unlock(&arg4, 0);
64274462Salfred	res.cookie = arg->cookie;
64374462Salfred
64474462Salfred	transmit_result(NLM_UNLOCK_RES, &res,
64574462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
64674462Salfred	return (NULL);
64774462Salfred}
64874462Salfred
64974462Salfred/* ------------------------------------------------------------------------- */
65074462Salfred/*
65174462Salfred * Client-side pseudo-RPCs for results.  Note that for the client there
65274462Salfred * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
65374462Salfred * version returns the results in the RPC result, and so the client
65474462Salfred * does not normally receive incoming RPCs.
65574462Salfred *
65674462Salfred * The exception to this is nlm_granted(), which is genuinely an RPC
65774462Salfred * call from the server to the client - a 'call-back' in normal procedure
65874462Salfred * call terms.
65974462Salfred */
66074462Salfred
66174462Salfred/* nlm_granted ------------------------------------------------------------- */
66274462Salfred/*
66374462Salfred * Purpose:	Receive notification that formerly blocked lock now granted
66474462Salfred * Returns:	always success ('granted')
66574462Salfred * Notes:
66674462Salfred */
66774462Salfrednlm_res *
66874462Salfrednlm_granted_1_svc(arg, rqstp)
66974462Salfred	nlm_testargs *arg;
67074462Salfred	struct svc_req *rqstp;
67174462Salfred{
67274462Salfred	static nlm_res res;
67374462Salfred
67474462Salfred	if (debug_level)
67574462Salfred		log_from_addr("nlm_granted", rqstp);
67674462Salfred
67775631Salfred	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
67875631Salfred		nlm_granted, NULL, NLM_VERS) == 0 ?
67975631Salfred		nlm_granted : nlm_denied;
68075631Salfred
68174462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
68274462Salfred	res.cookie = arg->cookie;
68374462Salfred
68474462Salfred	return (&res);
68574462Salfred}
68674462Salfred
68774462Salfredvoid *
68874462Salfrednlm_granted_msg_1_svc(arg, rqstp)
68974462Salfred	nlm_testargs *arg;
69074462Salfred	struct svc_req *rqstp;
69174462Salfred{
69274462Salfred	static nlm_res res;
69374462Salfred
69474462Salfred	if (debug_level)
69574462Salfred		log_from_addr("nlm_granted_msg", rqstp);
69674462Salfred
69774462Salfred	res.cookie = arg->cookie;
698114993Srwatson	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
699114993Srwatson		nlm_granted, NULL, NLM_VERS) == 0 ?
700114993Srwatson		nlm_granted : nlm_denied;
701114993Srwatson
70274462Salfred	transmit_result(NLM_GRANTED_RES, &res,
70374462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
70474462Salfred	return (NULL);
70574462Salfred}
70674462Salfred
70774462Salfred/* nlm_test_res ------------------------------------------------------------ */
70874462Salfred/*
70974462Salfred * Purpose:	Accept result from earlier nlm_test_msg() call
71074462Salfred * Returns:	Nothing
71174462Salfred */
71274462Salfredvoid *
71374462Salfrednlm_test_res_1_svc(arg, rqstp)
71474462Salfred	nlm_testres *arg;
71574462Salfred	struct svc_req *rqstp;
71674462Salfred{
71774462Salfred	if (debug_level)
71874462Salfred		log_from_addr("nlm_test_res", rqstp);
71975631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat,
72075631Salfred		&arg->stat.nlm_testrply_u.holder.svid, NLM_VERS);
72174462Salfred	return (NULL);
72274462Salfred}
72374462Salfred
72474462Salfred/* nlm_lock_res ------------------------------------------------------------ */
72574462Salfred/*
72674462Salfred * Purpose:	Accept result from earlier nlm_lock_msg() call
72774462Salfred * Returns:	Nothing
72874462Salfred */
72974462Salfredvoid *
73074462Salfrednlm_lock_res_1_svc(arg, rqstp)
73174462Salfred	nlm_res *arg;
73274462Salfred	struct svc_req *rqstp;
73374462Salfred{
73474462Salfred	if (debug_level)
73574462Salfred		log_from_addr("nlm_lock_res", rqstp);
73674462Salfred
73775631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
73875631Salfred
73974462Salfred	return (NULL);
74074462Salfred}
74174462Salfred
74274462Salfred/* nlm_cancel_res ---------------------------------------------------------- */
74374462Salfred/*
74474462Salfred * Purpose:	Accept result from earlier nlm_cancel_msg() call
74574462Salfred * Returns:	Nothing
74674462Salfred */
74774462Salfredvoid *
74874462Salfrednlm_cancel_res_1_svc(arg, rqstp)
74992911Salfred	nlm_res *arg __unused;
75074462Salfred	struct svc_req *rqstp;
75174462Salfred{
75274462Salfred	if (debug_level)
75374462Salfred		log_from_addr("nlm_cancel_res", rqstp);
75474462Salfred	return (NULL);
75574462Salfred}
75674462Salfred
75774462Salfred/* nlm_unlock_res ---------------------------------------------------------- */
75874462Salfred/*
75974462Salfred * Purpose:	Accept result from earlier nlm_unlock_msg() call
76074462Salfred * Returns:	Nothing
76174462Salfred */
76274462Salfredvoid *
76374462Salfrednlm_unlock_res_1_svc(arg, rqstp)
76474462Salfred	nlm_res *arg;
76574462Salfred	struct svc_req *rqstp;
76674462Salfred{
76774462Salfred	if (debug_level)
76874462Salfred		log_from_addr("nlm_unlock_res", rqstp);
76975631Salfred
77086300Salfred	lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
77175631Salfred
77274462Salfred	return (NULL);
77374462Salfred}
77474462Salfred
77574462Salfred/* nlm_granted_res --------------------------------------------------------- */
77674462Salfred/*
77774462Salfred * Purpose:	Accept result from earlier nlm_granted_msg() call
77874462Salfred * Returns:	Nothing
77974462Salfred */
78074462Salfredvoid *
78174462Salfrednlm_granted_res_1_svc(arg, rqstp)
78292911Salfred	nlm_res *arg __unused;
78374462Salfred	struct svc_req *rqstp;
78474462Salfred{
78574462Salfred	if (debug_level)
78674462Salfred		log_from_addr("nlm_granted_res", rqstp);
78774462Salfred	return (NULL);
78874462Salfred}
78974462Salfred
79074462Salfred/* ------------------------------------------------------------------------- */
79174462Salfred/*
79274462Salfred * Calls for PCNFS locking (aka non-monitored locking, no involvement
79374462Salfred * of rpc.statd).
79474462Salfred *
79574462Salfred * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
79674462Salfred */
79774462Salfred
79874462Salfred/* nlm_share --------------------------------------------------------------- */
79974462Salfred/*
80074462Salfred * Purpose:	Establish a DOS-style lock
80174462Salfred * Returns:	success or failure
80274462Salfred * Notes:	Blocking locks are not supported - client is expected
80374462Salfred *		to retry if required.
80474462Salfred */
80574462Salfrednlm_shareres *
80674462Salfrednlm_share_3_svc(arg, rqstp)
80774462Salfred	nlm_shareargs *arg;
80874462Salfred	struct svc_req *rqstp;
80974462Salfred{
81074462Salfred	static nlm_shareres res;
81174462Salfred
81274462Salfred	if (debug_level)
81374462Salfred		log_from_addr("nlm_share", rqstp);
81474462Salfred
81574462Salfred	res.cookie = arg->cookie;
81674462Salfred	res.stat = nlm_granted;
81774462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
81874462Salfred	return (&res);
81974462Salfred}
82074462Salfred
82174462Salfred/* nlm_unshare ------------------------------------------------------------ */
82274462Salfred/*
82374462Salfred * Purpose:	Release a DOS-style lock
82474462Salfred * Returns:	nlm_granted, unless in grace period
82574462Salfred * Notes:
82674462Salfred */
82774462Salfrednlm_shareres *
82874462Salfrednlm_unshare_3_svc(arg, rqstp)
82974462Salfred	nlm_shareargs *arg;
83074462Salfred	struct svc_req *rqstp;
83174462Salfred{
83274462Salfred	static nlm_shareres res;
83374462Salfred
83474462Salfred	if (debug_level)
83574462Salfred		log_from_addr("nlm_unshare", rqstp);
83674462Salfred
83774462Salfred	res.cookie = arg->cookie;
83874462Salfred	res.stat = nlm_granted;
83974462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
84074462Salfred	return (&res);
84174462Salfred}
84274462Salfred
84374462Salfred/* nlm_nm_lock ------------------------------------------------------------ */
84474462Salfred/*
84574462Salfred * Purpose:	non-monitored version of nlm_lock()
84674462Salfred * Returns:	as for nlm_lock()
84774462Salfred * Notes:	These locks are in the same style as the standard nlm_lock,
84874462Salfred *		but the rpc.statd should not be called to establish a
84974462Salfred *		monitor for the client machine, since that machine is
85074462Salfred *		declared not to be running a rpc.statd, and so would not
85174462Salfred *		respond to the statd protocol.
85274462Salfred */
85374462Salfrednlm_res *
85474462Salfrednlm_nm_lock_3_svc(arg, rqstp)
85574462Salfred	nlm_lockargs *arg;
85674462Salfred	struct svc_req *rqstp;
85774462Salfred{
85874462Salfred	static nlm_res res;
85974462Salfred
86074462Salfred	if (debug_level)
86174462Salfred		log_from_addr("nlm_nm_lock", rqstp);
86274462Salfred
86374462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
86474462Salfred	res.cookie = arg->cookie;
86574462Salfred	res.stat.stat = nlm_granted;
86674462Salfred	return (&res);
86774462Salfred}
86874462Salfred
86974462Salfred/* nlm_free_all ------------------------------------------------------------ */
87074462Salfred/*
87174462Salfred * Purpose:	Release all locks held by a named client
87274462Salfred * Returns:	Nothing
87374462Salfred * Notes:	Potential denial of service security problem here - the
87474462Salfred *		locks to be released are specified by a host name, independent
87574462Salfred *		of the address from which the request has arrived.
87674462Salfred *		Should probably be rejected if the named host has been
87774462Salfred *		using monitored locks.
87874462Salfred */
87974462Salfredvoid *
88074462Salfrednlm_free_all_3_svc(arg, rqstp)
88192911Salfred	nlm_notify *arg __unused;
88274462Salfred	struct svc_req *rqstp;
88374462Salfred{
88474462Salfred	static char dummy;
88574462Salfred
88674462Salfred	if (debug_level)
88774462Salfred		log_from_addr("nlm_free_all", rqstp);
88874462Salfred	return (&dummy);
88974462Salfred}
89074462Salfred
89174462Salfred/* calls for nlm version 4 (NFSv3) */
89274462Salfred/* nlm_test ---------------------------------------------------------------- */
89374462Salfred/*
89474462Salfred * Purpose:	Test whether a specified lock would be granted if requested
89574462Salfred * Returns:	nlm_granted (or error code)
89674462Salfred * Notes:
89774462Salfred */
89874462Salfrednlm4_testres *
89974462Salfrednlm4_test_4_svc(arg, rqstp)
90074462Salfred	nlm4_testargs *arg;
90174462Salfred	struct svc_req *rqstp;
90274462Salfred{
90374462Salfred	static nlm4_testres res;
90474462Salfred	struct nlm4_holder *holder;
90574462Salfred
90674462Salfred	if (debug_level)
90774462Salfred		log_from_addr("nlm4_test", rqstp);
90884923Salfred	if (debug_level > 5) {
90984923Salfred		syslog(LOG_DEBUG, "Locking arguments:\n");
91084923Salfred		log_netobj(&(arg->cookie));
91184923Salfred		syslog(LOG_DEBUG, "Alock arguments:\n");
91284923Salfred		syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
91384923Salfred		syslog(LOG_DEBUG, "File Handle:\n");
91484923Salfred		log_netobj(&(arg->alock.fh));
91584923Salfred		syslog(LOG_DEBUG, "Owner Handle:\n");
91684923Salfred		log_netobj(&(arg->alock.oh));
91784923Salfred		syslog(LOG_DEBUG, "SVID:        %d\n", arg->alock.svid);
91886319Salfred		syslog(LOG_DEBUG, "Lock Offset: %llu\n",
91986319Salfred		    (unsigned long long)arg->alock.l_offset);
92086319Salfred		syslog(LOG_DEBUG, "Lock Length: %llu\n",
92186319Salfred		    (unsigned long long)arg->alock.l_len);
92284923Salfred		syslog(LOG_DEBUG, "Exclusive:   %s\n",
92384923Salfred		    (arg->exclusive ? "true" : "false"));
92484923Salfred	}
92574462Salfred
92684923Salfred	holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
92774462Salfred
92874462Salfred	/*
92974462Salfred	 * Copy the cookie from the argument into the result.  Note that this
93074462Salfred	 * is slightly hazardous, as the structure contains a pointer to a
93174462Salfred	 * malloc()ed buffer that will get freed by the caller.  However, the
93274462Salfred	 * main function transmits the result before freeing the argument
93374462Salfred	 * so it is in fact safe.
93474462Salfred	 */
93574462Salfred	res.cookie = arg->cookie;
93674462Salfred	if (holder == NULL) {
93774462Salfred		res.stat.stat = nlm4_granted;
93874462Salfred	} else {
93974462Salfred		res.stat.stat = nlm4_denied;
94074462Salfred		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
94174462Salfred		    sizeof(struct nlm4_holder));
94274462Salfred	}
94374462Salfred	return (&res);
94474462Salfred}
94574462Salfred
94674462Salfredvoid *
94774462Salfrednlm4_test_msg_4_svc(arg, rqstp)
94874462Salfred	nlm4_testargs *arg;
94974462Salfred	struct svc_req *rqstp;
95074462Salfred{
95174462Salfred	nlm4_testres res;
95274462Salfred	static char dummy;
95374462Salfred	struct sockaddr *addr;
95474462Salfred	CLIENT *cli;
95574462Salfred	int success;
95674462Salfred	struct timeval timeo;
95774462Salfred	struct nlm4_holder *holder;
95874462Salfred
95974462Salfred	if (debug_level)
96074462Salfred		log_from_addr("nlm4_test_msg", rqstp);
96174462Salfred
96284923Salfred	holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
96374462Salfred
96474462Salfred	res.cookie = arg->cookie;
96574462Salfred	if (holder == NULL) {
96674462Salfred		res.stat.stat = nlm4_granted;
96774462Salfred	} else {
96874462Salfred		res.stat.stat = nlm4_denied;
96974462Salfred		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
97074462Salfred		    sizeof(struct nlm4_holder));
97174462Salfred	}
97274462Salfred
97374462Salfred	/*
97474462Salfred	 * nlm_test has different result type to the other operations, so
97574462Salfred	 * can't use transmit4_result() in this case
97674462Salfred	 */
97774462Salfred	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
97874462Salfred	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
97974462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
98074462Salfred		timeo.tv_usec = 0;
98174462Salfred
98274462Salfred		success = clnt_call(cli, NLM4_TEST_RES, xdr_nlm4_testres,
98374462Salfred		    &res, xdr_void, &dummy, timeo);
98474462Salfred
98574462Salfred		if (debug_level > 2)
98674462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d", success);
98774462Salfred	}
98874462Salfred	return (NULL);
98974462Salfred}
99074462Salfred
99174462Salfred/* nlm_lock ---------------------------------------------------------------- */
99274462Salfred/*
99374462Salfred * Purposes:	Establish a lock
99474462Salfred * Returns:	granted, denied or blocked
99574462Salfred * Notes:	*** grace period support missing
99674462Salfred */
99774462Salfrednlm4_res *
99874462Salfrednlm4_lock_4_svc(arg, rqstp)
99974462Salfred	nlm4_lockargs *arg;
100074462Salfred	struct svc_req *rqstp;
100174462Salfred{
100274462Salfred	static nlm4_res res;
100374462Salfred
100474462Salfred	if (debug_level)
100574462Salfred		log_from_addr("nlm4_lock", rqstp);
100684923Salfred	if (debug_level > 5) {
100784923Salfred		syslog(LOG_DEBUG, "Locking arguments:\n");
100884923Salfred		log_netobj(&(arg->cookie));
100984923Salfred		syslog(LOG_DEBUG, "Alock arguments:\n");
101084923Salfred		syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
101184923Salfred		syslog(LOG_DEBUG, "File Handle:\n");
101284923Salfred		log_netobj(&(arg->alock.fh));
101384923Salfred		syslog(LOG_DEBUG, "Owner Handle:\n");
101484923Salfred		log_netobj(&(arg->alock.oh));
101584923Salfred		syslog(LOG_DEBUG, "SVID:        %d\n", arg->alock.svid);
101686319Salfred		syslog(LOG_DEBUG, "Lock Offset: %llu\n",
101786319Salfred		    (unsigned long long)arg->alock.l_offset);
101886319Salfred		syslog(LOG_DEBUG, "Lock Length: %llu\n",
101986319Salfred		    (unsigned long long)arg->alock.l_len);
102084923Salfred		syslog(LOG_DEBUG, "Block:       %s\n", (arg->block ? "true" : "false"));
102184923Salfred		syslog(LOG_DEBUG, "Exclusive:   %s\n", (arg->exclusive ? "true" : "false"));
102284923Salfred		syslog(LOG_DEBUG, "Reclaim:     %s\n", (arg->reclaim ? "true" : "false"));
102384923Salfred		syslog(LOG_DEBUG, "State num:   %d\n", arg->state);
102484923Salfred	}
102574462Salfred
102674462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_4() */
102774462Salfred	res.cookie = arg->cookie;
102874462Salfred
102974462Salfred	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_V4);
103074462Salfred	return (&res);
103174462Salfred}
103274462Salfred
103374462Salfredvoid *
103474462Salfrednlm4_lock_msg_4_svc(arg, rqstp)
103574462Salfred	nlm4_lockargs *arg;
103674462Salfred	struct svc_req *rqstp;
103774462Salfred{
103874462Salfred	static nlm4_res res;
103974462Salfred
104074462Salfred	if (debug_level)
104174462Salfred		log_from_addr("nlm4_lock_msg", rqstp);
104274462Salfred
104374462Salfred	res.cookie = arg->cookie;
104474462Salfred	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4);
104574462Salfred	transmit4_result(NLM4_LOCK_RES, &res,
104674462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
104774462Salfred
104874462Salfred	return (NULL);
104974462Salfred}
105074462Salfred
105174462Salfred/* nlm_cancel -------------------------------------------------------------- */
105274462Salfred/*
105374462Salfred * Purpose:	Cancel a blocked lock request
105474462Salfred * Returns:	granted or denied
105574462Salfred * Notes:
105674462Salfred */
105774462Salfrednlm4_res *
105874462Salfrednlm4_cancel_4_svc(arg, rqstp)
105974462Salfred	nlm4_cancargs *arg;
106074462Salfred	struct svc_req *rqstp;
106174462Salfred{
106274462Salfred	static nlm4_res res;
106374462Salfred
106474462Salfred	if (debug_level)
106574462Salfred		log_from_addr("nlm4_cancel", rqstp);
106674462Salfred
106774462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
106874462Salfred	res.cookie = arg->cookie;
106974462Salfred
107074462Salfred	/*
107174462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
107274462Salfred	 * a lock to cancel, so this call always fails.
107374462Salfred	 */
107474462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL);
107574462Salfred	return (&res);
107674462Salfred}
107774462Salfred
107874462Salfredvoid *
107974462Salfrednlm4_cancel_msg_4_svc(arg, rqstp)
108074462Salfred	nlm4_cancargs *arg;
108174462Salfred	struct svc_req *rqstp;
108274462Salfred{
108374462Salfred	static nlm4_res res;
108474462Salfred
108574462Salfred	if (debug_level)
108674462Salfred		log_from_addr("nlm4_cancel_msg", rqstp);
108774462Salfred
108874462Salfred	res.cookie = arg->cookie;
108974462Salfred	/*
109074462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
109174462Salfred	 * a lock to cancel, so this call always fails.
109274462Salfred	 */
109374462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4);
109474462Salfred	transmit4_result(NLM4_CANCEL_RES, &res,
109574462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
109674462Salfred	return (NULL);
109774462Salfred}
109874462Salfred
109974462Salfred/* nlm_unlock -------------------------------------------------------------- */
110074462Salfred/*
110174462Salfred * Purpose:	Release an existing lock
110274462Salfred * Returns:	Always granted, unless during grace period
110374462Salfred * Notes:	"no such lock" error condition is ignored, as the
110474462Salfred *		protocol uses unreliable UDP datagrams, and may well
110574462Salfred *		re-try an unlock that has already succeeded.
110674462Salfred */
110774462Salfrednlm4_res *
110874462Salfrednlm4_unlock_4_svc(arg, rqstp)
110974462Salfred	nlm4_unlockargs *arg;
111074462Salfred	struct svc_req *rqstp;
111174462Salfred{
111274462Salfred	static nlm4_res res;
111374462Salfred
111474462Salfred	if (debug_level)
111574462Salfred		log_from_addr("nlm4_unlock", rqstp);
111674462Salfred
111774462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_V4);
111874462Salfred	res.cookie = arg->cookie;
111974462Salfred
112074462Salfred	return (&res);
112174462Salfred}
112274462Salfred
112374462Salfredvoid *
112474462Salfrednlm4_unlock_msg_4_svc(arg, rqstp)
112574462Salfred	nlm4_unlockargs *arg;
112674462Salfred	struct svc_req *rqstp;
112774462Salfred{
112874462Salfred	static nlm4_res res;
112974462Salfred
113074462Salfred	if (debug_level)
113174462Salfred		log_from_addr("nlm4_unlock_msg", rqstp);
113274462Salfred
113374462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_V4);
113474462Salfred	res.cookie = arg->cookie;
113574462Salfred
113674462Salfred	transmit4_result(NLM4_UNLOCK_RES, &res,
113774462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
113874462Salfred	return (NULL);
113974462Salfred}
114074462Salfred
114174462Salfred/* ------------------------------------------------------------------------- */
114274462Salfred/*
114374462Salfred * Client-side pseudo-RPCs for results.  Note that for the client there
114474462Salfred * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
114574462Salfred * version returns the results in the RPC result, and so the client
114674462Salfred * does not normally receive incoming RPCs.
114774462Salfred *
114874462Salfred * The exception to this is nlm_granted(), which is genuinely an RPC
114974462Salfred * call from the server to the client - a 'call-back' in normal procedure
115074462Salfred * call terms.
115174462Salfred */
115274462Salfred
115374462Salfred/* nlm_granted ------------------------------------------------------------- */
115474462Salfred/*
115574462Salfred * Purpose:	Receive notification that formerly blocked lock now granted
115674462Salfred * Returns:	always success ('granted')
115774462Salfred * Notes:
115874462Salfred */
115974462Salfrednlm4_res *
116074462Salfrednlm4_granted_4_svc(arg, rqstp)
116174462Salfred	nlm4_testargs *arg;
116274462Salfred	struct svc_req *rqstp;
116374462Salfred{
116474462Salfred	static nlm4_res res;
116574462Salfred
116674462Salfred	if (debug_level)
116774462Salfred		log_from_addr("nlm4_granted", rqstp);
116874462Salfred
116975631Salfred	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
117075631Salfred		nlm4_granted, NULL, NLM_VERS4) == 0 ?
117175631Salfred		nlm4_granted : nlm4_denied;
117275631Salfred
117374462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
117474462Salfred	res.cookie = arg->cookie;
117574462Salfred
117674462Salfred	return (&res);
117774462Salfred}
117874462Salfred
117974462Salfredvoid *
118074462Salfrednlm4_granted_msg_4_svc(arg, rqstp)
118174462Salfred	nlm4_testargs *arg;
118274462Salfred	struct svc_req *rqstp;
118374462Salfred{
118474462Salfred	static nlm4_res res;
118574462Salfred
118674462Salfred	if (debug_level)
118774462Salfred		log_from_addr("nlm4_granted_msg", rqstp);
118874462Salfred
118974462Salfred	res.cookie = arg->cookie;
1190114993Srwatson	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
1191114993Srwatson		nlm4_granted, NULL, NLM_VERS4) == 0 ?
1192114993Srwatson		nlm4_granted : nlm4_denied;
119374462Salfred	transmit4_result(NLM4_GRANTED_RES, &res,
119474462Salfred	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
119574462Salfred	return (NULL);
119674462Salfred}
119774462Salfred
119874462Salfred/* nlm_test_res ------------------------------------------------------------ */
119974462Salfred/*
120074462Salfred * Purpose:	Accept result from earlier nlm_test_msg() call
120174462Salfred * Returns:	Nothing
120274462Salfred */
120374462Salfredvoid *
120474462Salfrednlm4_test_res_4_svc(arg, rqstp)
120574462Salfred	nlm4_testres *arg;
120674462Salfred	struct svc_req *rqstp;
120774462Salfred{
120874462Salfred	if (debug_level)
120974462Salfred		log_from_addr("nlm4_test_res", rqstp);
121075631Salfred
121175631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat,
121275631Salfred		(int *)&arg->stat.nlm4_testrply_u.holder.svid,
121375631Salfred		NLM_VERS4);
121474462Salfred	return (NULL);
121574462Salfred}
121674462Salfred
121774462Salfred/* nlm_lock_res ------------------------------------------------------------ */
121874462Salfred/*
121974462Salfred * Purpose:	Accept result from earlier nlm_lock_msg() call
122074462Salfred * Returns:	Nothing
122174462Salfred */
122274462Salfredvoid *
122374462Salfrednlm4_lock_res_4_svc(arg, rqstp)
122474462Salfred	nlm4_res *arg;
122574462Salfred	struct svc_req *rqstp;
122674462Salfred{
122774462Salfred	if (debug_level)
122874462Salfred		log_from_addr("nlm4_lock_res", rqstp);
122974462Salfred
123075631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS4);
123175631Salfred
123274462Salfred	return (NULL);
123374462Salfred}
123474462Salfred
123574462Salfred/* nlm_cancel_res ---------------------------------------------------------- */
123674462Salfred/*
123774462Salfred * Purpose:	Accept result from earlier nlm_cancel_msg() call
123874462Salfred * Returns:	Nothing
123974462Salfred */
124074462Salfredvoid *
124174462Salfrednlm4_cancel_res_4_svc(arg, rqstp)
124292911Salfred	nlm4_res *arg __unused;
124374462Salfred	struct svc_req *rqstp;
124474462Salfred{
124574462Salfred	if (debug_level)
124674462Salfred		log_from_addr("nlm4_cancel_res", rqstp);
124774462Salfred	return (NULL);
124874462Salfred}
124974462Salfred
125074462Salfred/* nlm_unlock_res ---------------------------------------------------------- */
125174462Salfred/*
125274462Salfred * Purpose:	Accept result from earlier nlm_unlock_msg() call
125374462Salfred * Returns:	Nothing
125474462Salfred */
125574462Salfredvoid *
125674462Salfrednlm4_unlock_res_4_svc(arg, rqstp)
125792911Salfred	nlm4_res *arg __unused;
125874462Salfred	struct svc_req *rqstp;
125974462Salfred{
126074462Salfred	if (debug_level)
126174462Salfred		log_from_addr("nlm4_unlock_res", rqstp);
126274462Salfred	return (NULL);
126374462Salfred}
126474462Salfred
126574462Salfred/* nlm_granted_res --------------------------------------------------------- */
126674462Salfred/*
126774462Salfred * Purpose:	Accept result from earlier nlm_granted_msg() call
126874462Salfred * Returns:	Nothing
126974462Salfred */
127074462Salfredvoid *
127174462Salfrednlm4_granted_res_4_svc(arg, rqstp)
127292911Salfred	nlm4_res *arg __unused;
127374462Salfred	struct svc_req *rqstp;
127474462Salfred{
127574462Salfred	if (debug_level)
127674462Salfred		log_from_addr("nlm4_granted_res", rqstp);
127774462Salfred	return (NULL);
127874462Salfred}
127974462Salfred
128074462Salfred/* ------------------------------------------------------------------------- */
128174462Salfred/*
128274462Salfred * Calls for PCNFS locking (aka non-monitored locking, no involvement
128374462Salfred * of rpc.statd).
128474462Salfred *
128574462Salfred * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
128674462Salfred */
128774462Salfred
128874462Salfred/* nlm_share --------------------------------------------------------------- */
128974462Salfred/*
129074462Salfred * Purpose:	Establish a DOS-style lock
129174462Salfred * Returns:	success or failure
129274462Salfred * Notes:	Blocking locks are not supported - client is expected
129374462Salfred *		to retry if required.
129474462Salfred */
129574462Salfrednlm4_shareres *
129674462Salfrednlm4_share_4_svc(arg, rqstp)
129774462Salfred	nlm4_shareargs *arg;
129874462Salfred	struct svc_req *rqstp;
129974462Salfred{
130074462Salfred	static nlm4_shareres res;
130174462Salfred
130274462Salfred	if (debug_level)
130374462Salfred		log_from_addr("nlm4_share", rqstp);
130474462Salfred
130574462Salfred	res.cookie = arg->cookie;
130674462Salfred	res.stat = nlm4_granted;
130774462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
130874462Salfred	return (&res);
130974462Salfred}
131074462Salfred
131174462Salfred/* nlm4_unshare ------------------------------------------------------------ */
131274462Salfred/*
131374462Salfred * Purpose:	Release a DOS-style lock
131474462Salfred * Returns:	nlm_granted, unless in grace period
131574462Salfred * Notes:
131674462Salfred */
131774462Salfrednlm4_shareres *
131874462Salfrednlm4_unshare_4_svc(arg, rqstp)
131974462Salfred	nlm4_shareargs *arg;
132074462Salfred	struct svc_req *rqstp;
132174462Salfred{
132274462Salfred	static nlm4_shareres res;
132374462Salfred
132474462Salfred	if (debug_level)
132574462Salfred		log_from_addr("nlm_unshare", rqstp);
132674462Salfred
132774462Salfred	res.cookie = arg->cookie;
132874462Salfred	res.stat = nlm4_granted;
132974462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
133074462Salfred	return (&res);
133174462Salfred}
133274462Salfred
133374462Salfred/* nlm4_nm_lock ------------------------------------------------------------ */
133474462Salfred/*
133574462Salfred * Purpose:	non-monitored version of nlm4_lock()
133674462Salfred * Returns:	as for nlm4_lock()
133774462Salfred * Notes:	These locks are in the same style as the standard nlm4_lock,
133874462Salfred *		but the rpc.statd should not be called to establish a
133974462Salfred *		monitor for the client machine, since that machine is
134074462Salfred *		declared not to be running a rpc.statd, and so would not
134174462Salfred *		respond to the statd protocol.
134274462Salfred */
134374462Salfrednlm4_res *
134474462Salfrednlm4_nm_lock_4_svc(arg, rqstp)
134574462Salfred	nlm4_lockargs *arg;
134674462Salfred	struct svc_req *rqstp;
134774462Salfred{
134874462Salfred	static nlm4_res res;
134974462Salfred
135074462Salfred	if (debug_level)
135174462Salfred		log_from_addr("nlm4_nm_lock", rqstp);
135274462Salfred
135374462Salfred	/* copy cookie from arg to result.  See comment in nlm4_test_1() */
135474462Salfred	res.cookie = arg->cookie;
135574462Salfred	res.stat.stat = nlm4_granted;
135674462Salfred	return (&res);
135774462Salfred}
135874462Salfred
135974462Salfred/* nlm4_free_all ------------------------------------------------------------ */
136074462Salfred/*
136174462Salfred * Purpose:	Release all locks held by a named client
136274462Salfred * Returns:	Nothing
136374462Salfred * Notes:	Potential denial of service security problem here - the
136474462Salfred *		locks to be released are specified by a host name, independent
136574462Salfred *		of the address from which the request has arrived.
136674462Salfred *		Should probably be rejected if the named host has been
136774462Salfred *		using monitored locks.
136874462Salfred */
136974462Salfredvoid *
137074462Salfrednlm4_free_all_4_svc(arg, rqstp)
137192911Salfred	struct nlm4_notify *arg __unused;
137274462Salfred	struct svc_req *rqstp;
137374462Salfred{
137474462Salfred	static char dummy;
137574462Salfred
137674462Salfred	if (debug_level)
137774462Salfred		log_from_addr("nlm4_free_all", rqstp);
137874462Salfred	return (&dummy);
137974462Salfred}
138074462Salfred
138174462Salfred/* nlm_sm_notify --------------------------------------------------------- */
138274462Salfred/*
138374462Salfred * Purpose:	called by rpc.statd when a monitored host state changes.
138474462Salfred * Returns:	Nothing
138574462Salfred */
138674462Salfredvoid *
138774462Salfrednlm_sm_notify_0_svc(arg, rqstp)
138874462Salfred	struct nlm_sm_status *arg;
138992911Salfred	struct svc_req *rqstp __unused;
139074462Salfred{
139174462Salfred	static char dummy;
139274462Salfred	notify(arg->mon_name, arg->state);
139374462Salfred	return (&dummy);
139474462Salfred}
1395