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