lock_proc.c revision 86319
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 86319 2001-11-13 11:24:23Z 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 *));
6586319Salfredstatic void	log_netobj __P((netobj *obj));
6674462Salfredstatic int	addrcmp __P((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)
7774462Salfred	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;
19774462Salfred	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 */
36474462Salfredstatic void nlmtonlm4 __P((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;
69874462Salfred	res.stat.stat = nlm_granted;
69974462Salfred	transmit_result(NLM_GRANTED_RES, &res,
70074462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
70174462Salfred	return (NULL);
70274462Salfred}
70374462Salfred
70474462Salfred/* nlm_test_res ------------------------------------------------------------ */
70574462Salfred/*
70674462Salfred * Purpose:	Accept result from earlier nlm_test_msg() call
70774462Salfred * Returns:	Nothing
70874462Salfred */
70974462Salfredvoid *
71074462Salfrednlm_test_res_1_svc(arg, rqstp)
71174462Salfred	nlm_testres *arg;
71274462Salfred	struct svc_req *rqstp;
71374462Salfred{
71474462Salfred	if (debug_level)
71574462Salfred		log_from_addr("nlm_test_res", rqstp);
71675631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat,
71775631Salfred		&arg->stat.nlm_testrply_u.holder.svid, NLM_VERS);
71874462Salfred	return (NULL);
71974462Salfred}
72074462Salfred
72174462Salfred/* nlm_lock_res ------------------------------------------------------------ */
72274462Salfred/*
72374462Salfred * Purpose:	Accept result from earlier nlm_lock_msg() call
72474462Salfred * Returns:	Nothing
72574462Salfred */
72674462Salfredvoid *
72774462Salfrednlm_lock_res_1_svc(arg, rqstp)
72874462Salfred	nlm_res *arg;
72974462Salfred	struct svc_req *rqstp;
73074462Salfred{
73174462Salfred	if (debug_level)
73274462Salfred		log_from_addr("nlm_lock_res", rqstp);
73374462Salfred
73475631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
73575631Salfred
73674462Salfred	return (NULL);
73774462Salfred}
73874462Salfred
73974462Salfred/* nlm_cancel_res ---------------------------------------------------------- */
74074462Salfred/*
74174462Salfred * Purpose:	Accept result from earlier nlm_cancel_msg() call
74274462Salfred * Returns:	Nothing
74374462Salfred */
74474462Salfredvoid *
74574462Salfrednlm_cancel_res_1_svc(arg, rqstp)
74674462Salfred	nlm_res *arg;
74774462Salfred	struct svc_req *rqstp;
74874462Salfred{
74974462Salfred	if (debug_level)
75074462Salfred		log_from_addr("nlm_cancel_res", rqstp);
75174462Salfred	return (NULL);
75274462Salfred}
75374462Salfred
75474462Salfred/* nlm_unlock_res ---------------------------------------------------------- */
75574462Salfred/*
75674462Salfred * Purpose:	Accept result from earlier nlm_unlock_msg() call
75774462Salfred * Returns:	Nothing
75874462Salfred */
75974462Salfredvoid *
76074462Salfrednlm_unlock_res_1_svc(arg, rqstp)
76174462Salfred	nlm_res *arg;
76274462Salfred	struct svc_req *rqstp;
76374462Salfred{
76474462Salfred	if (debug_level)
76574462Salfred		log_from_addr("nlm_unlock_res", rqstp);
76675631Salfred
76786300Salfred	lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
76875631Salfred
76974462Salfred	return (NULL);
77074462Salfred}
77174462Salfred
77274462Salfred/* nlm_granted_res --------------------------------------------------------- */
77374462Salfred/*
77474462Salfred * Purpose:	Accept result from earlier nlm_granted_msg() call
77574462Salfred * Returns:	Nothing
77674462Salfred */
77774462Salfredvoid *
77874462Salfrednlm_granted_res_1_svc(arg, rqstp)
77974462Salfred	nlm_res *arg;
78074462Salfred	struct svc_req *rqstp;
78174462Salfred{
78274462Salfred	if (debug_level)
78374462Salfred		log_from_addr("nlm_granted_res", rqstp);
78474462Salfred	return (NULL);
78574462Salfred}
78674462Salfred
78774462Salfred/* ------------------------------------------------------------------------- */
78874462Salfred/*
78974462Salfred * Calls for PCNFS locking (aka non-monitored locking, no involvement
79074462Salfred * of rpc.statd).
79174462Salfred *
79274462Salfred * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
79374462Salfred */
79474462Salfred
79574462Salfred/* nlm_share --------------------------------------------------------------- */
79674462Salfred/*
79774462Salfred * Purpose:	Establish a DOS-style lock
79874462Salfred * Returns:	success or failure
79974462Salfred * Notes:	Blocking locks are not supported - client is expected
80074462Salfred *		to retry if required.
80174462Salfred */
80274462Salfrednlm_shareres *
80374462Salfrednlm_share_3_svc(arg, rqstp)
80474462Salfred	nlm_shareargs *arg;
80574462Salfred	struct svc_req *rqstp;
80674462Salfred{
80774462Salfred	static nlm_shareres res;
80874462Salfred
80974462Salfred	if (debug_level)
81074462Salfred		log_from_addr("nlm_share", rqstp);
81174462Salfred
81274462Salfred	res.cookie = arg->cookie;
81374462Salfred	res.stat = nlm_granted;
81474462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
81574462Salfred	return (&res);
81674462Salfred}
81774462Salfred
81874462Salfred/* nlm_unshare ------------------------------------------------------------ */
81974462Salfred/*
82074462Salfred * Purpose:	Release a DOS-style lock
82174462Salfred * Returns:	nlm_granted, unless in grace period
82274462Salfred * Notes:
82374462Salfred */
82474462Salfrednlm_shareres *
82574462Salfrednlm_unshare_3_svc(arg, rqstp)
82674462Salfred	nlm_shareargs *arg;
82774462Salfred	struct svc_req *rqstp;
82874462Salfred{
82974462Salfred	static nlm_shareres res;
83074462Salfred
83174462Salfred	if (debug_level)
83274462Salfred		log_from_addr("nlm_unshare", rqstp);
83374462Salfred
83474462Salfred	res.cookie = arg->cookie;
83574462Salfred	res.stat = nlm_granted;
83674462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
83774462Salfred	return (&res);
83874462Salfred}
83974462Salfred
84074462Salfred/* nlm_nm_lock ------------------------------------------------------------ */
84174462Salfred/*
84274462Salfred * Purpose:	non-monitored version of nlm_lock()
84374462Salfred * Returns:	as for nlm_lock()
84474462Salfred * Notes:	These locks are in the same style as the standard nlm_lock,
84574462Salfred *		but the rpc.statd should not be called to establish a
84674462Salfred *		monitor for the client machine, since that machine is
84774462Salfred *		declared not to be running a rpc.statd, and so would not
84874462Salfred *		respond to the statd protocol.
84974462Salfred */
85074462Salfrednlm_res *
85174462Salfrednlm_nm_lock_3_svc(arg, rqstp)
85274462Salfred	nlm_lockargs *arg;
85374462Salfred	struct svc_req *rqstp;
85474462Salfred{
85574462Salfred	static nlm_res res;
85674462Salfred
85774462Salfred	if (debug_level)
85874462Salfred		log_from_addr("nlm_nm_lock", rqstp);
85974462Salfred
86074462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
86174462Salfred	res.cookie = arg->cookie;
86274462Salfred	res.stat.stat = nlm_granted;
86374462Salfred	return (&res);
86474462Salfred}
86574462Salfred
86674462Salfred/* nlm_free_all ------------------------------------------------------------ */
86774462Salfred/*
86874462Salfred * Purpose:	Release all locks held by a named client
86974462Salfred * Returns:	Nothing
87074462Salfred * Notes:	Potential denial of service security problem here - the
87174462Salfred *		locks to be released are specified by a host name, independent
87274462Salfred *		of the address from which the request has arrived.
87374462Salfred *		Should probably be rejected if the named host has been
87474462Salfred *		using monitored locks.
87574462Salfred */
87674462Salfredvoid *
87774462Salfrednlm_free_all_3_svc(arg, rqstp)
87874462Salfred	nlm_notify *arg;
87974462Salfred	struct svc_req *rqstp;
88074462Salfred{
88174462Salfred	static char dummy;
88274462Salfred
88374462Salfred	if (debug_level)
88474462Salfred		log_from_addr("nlm_free_all", rqstp);
88574462Salfred	return (&dummy);
88674462Salfred}
88774462Salfred
88874462Salfred/* calls for nlm version 4 (NFSv3) */
88974462Salfred/* nlm_test ---------------------------------------------------------------- */
89074462Salfred/*
89174462Salfred * Purpose:	Test whether a specified lock would be granted if requested
89274462Salfred * Returns:	nlm_granted (or error code)
89374462Salfred * Notes:
89474462Salfred */
89574462Salfrednlm4_testres *
89674462Salfrednlm4_test_4_svc(arg, rqstp)
89774462Salfred	nlm4_testargs *arg;
89874462Salfred	struct svc_req *rqstp;
89974462Salfred{
90074462Salfred	static nlm4_testres res;
90174462Salfred	struct nlm4_holder *holder;
90274462Salfred
90374462Salfred	if (debug_level)
90474462Salfred		log_from_addr("nlm4_test", rqstp);
90584923Salfred	if (debug_level > 5) {
90684923Salfred		syslog(LOG_DEBUG, "Locking arguments:\n");
90784923Salfred		log_netobj(&(arg->cookie));
90884923Salfred		syslog(LOG_DEBUG, "Alock arguments:\n");
90984923Salfred		syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
91084923Salfred		syslog(LOG_DEBUG, "File Handle:\n");
91184923Salfred		log_netobj(&(arg->alock.fh));
91284923Salfred		syslog(LOG_DEBUG, "Owner Handle:\n");
91384923Salfred		log_netobj(&(arg->alock.oh));
91484923Salfred		syslog(LOG_DEBUG, "SVID:        %d\n", arg->alock.svid);
91586319Salfred		syslog(LOG_DEBUG, "Lock Offset: %llu\n",
91686319Salfred		    (unsigned long long)arg->alock.l_offset);
91786319Salfred		syslog(LOG_DEBUG, "Lock Length: %llu\n",
91886319Salfred		    (unsigned long long)arg->alock.l_len);
91984923Salfred		syslog(LOG_DEBUG, "Exclusive:   %s\n",
92084923Salfred		    (arg->exclusive ? "true" : "false"));
92184923Salfred	}
92274462Salfred
92384923Salfred	holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
92474462Salfred
92574462Salfred	/*
92674462Salfred	 * Copy the cookie from the argument into the result.  Note that this
92774462Salfred	 * is slightly hazardous, as the structure contains a pointer to a
92874462Salfred	 * malloc()ed buffer that will get freed by the caller.  However, the
92974462Salfred	 * main function transmits the result before freeing the argument
93074462Salfred	 * so it is in fact safe.
93174462Salfred	 */
93274462Salfred	res.cookie = arg->cookie;
93374462Salfred	if (holder == NULL) {
93474462Salfred		res.stat.stat = nlm4_granted;
93574462Salfred	} else {
93674462Salfred		res.stat.stat = nlm4_denied;
93774462Salfred		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
93874462Salfred		    sizeof(struct nlm4_holder));
93974462Salfred	}
94074462Salfred	return (&res);
94174462Salfred}
94274462Salfred
94374462Salfredvoid *
94474462Salfrednlm4_test_msg_4_svc(arg, rqstp)
94574462Salfred	nlm4_testargs *arg;
94674462Salfred	struct svc_req *rqstp;
94774462Salfred{
94874462Salfred	nlm4_testres res;
94974462Salfred	static char dummy;
95074462Salfred	struct sockaddr *addr;
95174462Salfred	CLIENT *cli;
95274462Salfred	int success;
95374462Salfred	struct timeval timeo;
95474462Salfred	struct nlm4_holder *holder;
95574462Salfred
95674462Salfred	if (debug_level)
95774462Salfred		log_from_addr("nlm4_test_msg", rqstp);
95874462Salfred
95984923Salfred	holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
96074462Salfred
96174462Salfred	res.cookie = arg->cookie;
96274462Salfred	if (holder == NULL) {
96374462Salfred		res.stat.stat = nlm4_granted;
96474462Salfred	} else {
96574462Salfred		res.stat.stat = nlm4_denied;
96674462Salfred		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
96774462Salfred		    sizeof(struct nlm4_holder));
96874462Salfred	}
96974462Salfred
97074462Salfred	/*
97174462Salfred	 * nlm_test has different result type to the other operations, so
97274462Salfred	 * can't use transmit4_result() in this case
97374462Salfred	 */
97474462Salfred	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
97574462Salfred	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
97674462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
97774462Salfred		timeo.tv_usec = 0;
97874462Salfred
97974462Salfred		success = clnt_call(cli, NLM4_TEST_RES, xdr_nlm4_testres,
98074462Salfred		    &res, xdr_void, &dummy, timeo);
98174462Salfred
98274462Salfred		if (debug_level > 2)
98374462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d", success);
98474462Salfred	}
98574462Salfred	return (NULL);
98674462Salfred}
98774462Salfred
98874462Salfred/* nlm_lock ---------------------------------------------------------------- */
98974462Salfred/*
99074462Salfred * Purposes:	Establish a lock
99174462Salfred * Returns:	granted, denied or blocked
99274462Salfred * Notes:	*** grace period support missing
99374462Salfred */
99474462Salfrednlm4_res *
99574462Salfrednlm4_lock_4_svc(arg, rqstp)
99674462Salfred	nlm4_lockargs *arg;
99774462Salfred	struct svc_req *rqstp;
99874462Salfred{
99974462Salfred	static nlm4_res res;
100074462Salfred
100174462Salfred	if (debug_level)
100274462Salfred		log_from_addr("nlm4_lock", rqstp);
100384923Salfred	if (debug_level > 5) {
100484923Salfred		syslog(LOG_DEBUG, "Locking arguments:\n");
100584923Salfred		log_netobj(&(arg->cookie));
100684923Salfred		syslog(LOG_DEBUG, "Alock arguments:\n");
100784923Salfred		syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
100884923Salfred		syslog(LOG_DEBUG, "File Handle:\n");
100984923Salfred		log_netobj(&(arg->alock.fh));
101084923Salfred		syslog(LOG_DEBUG, "Owner Handle:\n");
101184923Salfred		log_netobj(&(arg->alock.oh));
101284923Salfred		syslog(LOG_DEBUG, "SVID:        %d\n", arg->alock.svid);
101386319Salfred		syslog(LOG_DEBUG, "Lock Offset: %llu\n",
101486319Salfred		    (unsigned long long)arg->alock.l_offset);
101586319Salfred		syslog(LOG_DEBUG, "Lock Length: %llu\n",
101686319Salfred		    (unsigned long long)arg->alock.l_len);
101784923Salfred		syslog(LOG_DEBUG, "Block:       %s\n", (arg->block ? "true" : "false"));
101884923Salfred		syslog(LOG_DEBUG, "Exclusive:   %s\n", (arg->exclusive ? "true" : "false"));
101984923Salfred		syslog(LOG_DEBUG, "Reclaim:     %s\n", (arg->reclaim ? "true" : "false"));
102084923Salfred		syslog(LOG_DEBUG, "State num:   %d\n", arg->state);
102184923Salfred	}
102274462Salfred
102374462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_4() */
102474462Salfred	res.cookie = arg->cookie;
102574462Salfred
102674462Salfred	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_V4);
102774462Salfred	return (&res);
102874462Salfred}
102974462Salfred
103074462Salfredvoid *
103174462Salfrednlm4_lock_msg_4_svc(arg, rqstp)
103274462Salfred	nlm4_lockargs *arg;
103374462Salfred	struct svc_req *rqstp;
103474462Salfred{
103574462Salfred	static nlm4_res res;
103674462Salfred
103774462Salfred	if (debug_level)
103874462Salfred		log_from_addr("nlm4_lock_msg", rqstp);
103974462Salfred
104074462Salfred	res.cookie = arg->cookie;
104174462Salfred	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4);
104274462Salfred	transmit4_result(NLM4_LOCK_RES, &res,
104374462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
104474462Salfred
104574462Salfred	return (NULL);
104674462Salfred}
104774462Salfred
104874462Salfred/* nlm_cancel -------------------------------------------------------------- */
104974462Salfred/*
105074462Salfred * Purpose:	Cancel a blocked lock request
105174462Salfred * Returns:	granted or denied
105274462Salfred * Notes:
105374462Salfred */
105474462Salfrednlm4_res *
105574462Salfrednlm4_cancel_4_svc(arg, rqstp)
105674462Salfred	nlm4_cancargs *arg;
105774462Salfred	struct svc_req *rqstp;
105874462Salfred{
105974462Salfred	static nlm4_res res;
106074462Salfred
106174462Salfred	if (debug_level)
106274462Salfred		log_from_addr("nlm4_cancel", rqstp);
106374462Salfred
106474462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
106574462Salfred	res.cookie = arg->cookie;
106674462Salfred
106774462Salfred	/*
106874462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
106974462Salfred	 * a lock to cancel, so this call always fails.
107074462Salfred	 */
107174462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL);
107274462Salfred	return (&res);
107374462Salfred}
107474462Salfred
107574462Salfredvoid *
107674462Salfrednlm4_cancel_msg_4_svc(arg, rqstp)
107774462Salfred	nlm4_cancargs *arg;
107874462Salfred	struct svc_req *rqstp;
107974462Salfred{
108074462Salfred	static nlm4_res res;
108174462Salfred
108274462Salfred	if (debug_level)
108374462Salfred		log_from_addr("nlm4_cancel_msg", rqstp);
108474462Salfred
108574462Salfred	res.cookie = arg->cookie;
108674462Salfred	/*
108774462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
108874462Salfred	 * a lock to cancel, so this call always fails.
108974462Salfred	 */
109074462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4);
109174462Salfred	transmit4_result(NLM4_CANCEL_RES, &res,
109274462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
109374462Salfred	return (NULL);
109474462Salfred}
109574462Salfred
109674462Salfred/* nlm_unlock -------------------------------------------------------------- */
109774462Salfred/*
109874462Salfred * Purpose:	Release an existing lock
109974462Salfred * Returns:	Always granted, unless during grace period
110074462Salfred * Notes:	"no such lock" error condition is ignored, as the
110174462Salfred *		protocol uses unreliable UDP datagrams, and may well
110274462Salfred *		re-try an unlock that has already succeeded.
110374462Salfred */
110474462Salfrednlm4_res *
110574462Salfrednlm4_unlock_4_svc(arg, rqstp)
110674462Salfred	nlm4_unlockargs *arg;
110774462Salfred	struct svc_req *rqstp;
110874462Salfred{
110974462Salfred	static nlm4_res res;
111074462Salfred
111174462Salfred	if (debug_level)
111274462Salfred		log_from_addr("nlm4_unlock", rqstp);
111374462Salfred
111474462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_V4);
111574462Salfred	res.cookie = arg->cookie;
111674462Salfred
111774462Salfred	return (&res);
111874462Salfred}
111974462Salfred
112074462Salfredvoid *
112174462Salfrednlm4_unlock_msg_4_svc(arg, rqstp)
112274462Salfred	nlm4_unlockargs *arg;
112374462Salfred	struct svc_req *rqstp;
112474462Salfred{
112574462Salfred	static nlm4_res res;
112674462Salfred
112774462Salfred	if (debug_level)
112874462Salfred		log_from_addr("nlm4_unlock_msg", rqstp);
112974462Salfred
113074462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_V4);
113174462Salfred	res.cookie = arg->cookie;
113274462Salfred
113374462Salfred	transmit4_result(NLM4_UNLOCK_RES, &res,
113474462Salfred	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
113574462Salfred	return (NULL);
113674462Salfred}
113774462Salfred
113874462Salfred/* ------------------------------------------------------------------------- */
113974462Salfred/*
114074462Salfred * Client-side pseudo-RPCs for results.  Note that for the client there
114174462Salfred * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
114274462Salfred * version returns the results in the RPC result, and so the client
114374462Salfred * does not normally receive incoming RPCs.
114474462Salfred *
114574462Salfred * The exception to this is nlm_granted(), which is genuinely an RPC
114674462Salfred * call from the server to the client - a 'call-back' in normal procedure
114774462Salfred * call terms.
114874462Salfred */
114974462Salfred
115074462Salfred/* nlm_granted ------------------------------------------------------------- */
115174462Salfred/*
115274462Salfred * Purpose:	Receive notification that formerly blocked lock now granted
115374462Salfred * Returns:	always success ('granted')
115474462Salfred * Notes:
115574462Salfred */
115674462Salfrednlm4_res *
115774462Salfrednlm4_granted_4_svc(arg, rqstp)
115874462Salfred	nlm4_testargs *arg;
115974462Salfred	struct svc_req *rqstp;
116074462Salfred{
116174462Salfred	static nlm4_res res;
116274462Salfred
116374462Salfred	if (debug_level)
116474462Salfred		log_from_addr("nlm4_granted", rqstp);
116574462Salfred
116675631Salfred	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
116775631Salfred		nlm4_granted, NULL, NLM_VERS4) == 0 ?
116875631Salfred		nlm4_granted : nlm4_denied;
116975631Salfred
117074462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
117174462Salfred	res.cookie = arg->cookie;
117274462Salfred
117374462Salfred	return (&res);
117474462Salfred}
117574462Salfred
117674462Salfredvoid *
117774462Salfrednlm4_granted_msg_4_svc(arg, rqstp)
117874462Salfred	nlm4_testargs *arg;
117974462Salfred	struct svc_req *rqstp;
118074462Salfred{
118174462Salfred	static nlm4_res res;
118274462Salfred
118374462Salfred	if (debug_level)
118474462Salfred		log_from_addr("nlm4_granted_msg", rqstp);
118574462Salfred
118674462Salfred	res.cookie = arg->cookie;
118774462Salfred	res.stat.stat = nlm4_granted;
118874462Salfred	transmit4_result(NLM4_GRANTED_RES, &res,
118974462Salfred	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
119074462Salfred	return (NULL);
119174462Salfred}
119274462Salfred
119374462Salfred/* nlm_test_res ------------------------------------------------------------ */
119474462Salfred/*
119574462Salfred * Purpose:	Accept result from earlier nlm_test_msg() call
119674462Salfred * Returns:	Nothing
119774462Salfred */
119874462Salfredvoid *
119974462Salfrednlm4_test_res_4_svc(arg, rqstp)
120074462Salfred	nlm4_testres *arg;
120174462Salfred	struct svc_req *rqstp;
120274462Salfred{
120374462Salfred	if (debug_level)
120474462Salfred		log_from_addr("nlm4_test_res", rqstp);
120575631Salfred
120675631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat,
120775631Salfred		(int *)&arg->stat.nlm4_testrply_u.holder.svid,
120875631Salfred		NLM_VERS4);
120974462Salfred	return (NULL);
121074462Salfred}
121174462Salfred
121274462Salfred/* nlm_lock_res ------------------------------------------------------------ */
121374462Salfred/*
121474462Salfred * Purpose:	Accept result from earlier nlm_lock_msg() call
121574462Salfred * Returns:	Nothing
121674462Salfred */
121774462Salfredvoid *
121874462Salfrednlm4_lock_res_4_svc(arg, rqstp)
121974462Salfred	nlm4_res *arg;
122074462Salfred	struct svc_req *rqstp;
122174462Salfred{
122274462Salfred	if (debug_level)
122374462Salfred		log_from_addr("nlm4_lock_res", rqstp);
122474462Salfred
122575631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS4);
122675631Salfred
122774462Salfred	return (NULL);
122874462Salfred}
122974462Salfred
123074462Salfred/* nlm_cancel_res ---------------------------------------------------------- */
123174462Salfred/*
123274462Salfred * Purpose:	Accept result from earlier nlm_cancel_msg() call
123374462Salfred * Returns:	Nothing
123474462Salfred */
123574462Salfredvoid *
123674462Salfrednlm4_cancel_res_4_svc(arg, rqstp)
123774462Salfred	nlm4_res *arg;
123874462Salfred	struct svc_req *rqstp;
123974462Salfred{
124074462Salfred	if (debug_level)
124174462Salfred		log_from_addr("nlm4_cancel_res", rqstp);
124274462Salfred	return (NULL);
124374462Salfred}
124474462Salfred
124574462Salfred/* nlm_unlock_res ---------------------------------------------------------- */
124674462Salfred/*
124774462Salfred * Purpose:	Accept result from earlier nlm_unlock_msg() call
124874462Salfred * Returns:	Nothing
124974462Salfred */
125074462Salfredvoid *
125174462Salfrednlm4_unlock_res_4_svc(arg, rqstp)
125274462Salfred	nlm4_res *arg;
125374462Salfred	struct svc_req *rqstp;
125474462Salfred{
125574462Salfred	if (debug_level)
125674462Salfred		log_from_addr("nlm4_unlock_res", rqstp);
125774462Salfred	return (NULL);
125874462Salfred}
125974462Salfred
126074462Salfred/* nlm_granted_res --------------------------------------------------------- */
126174462Salfred/*
126274462Salfred * Purpose:	Accept result from earlier nlm_granted_msg() call
126374462Salfred * Returns:	Nothing
126474462Salfred */
126574462Salfredvoid *
126674462Salfrednlm4_granted_res_4_svc(arg, rqstp)
126774462Salfred	nlm4_res *arg;
126874462Salfred	struct svc_req *rqstp;
126974462Salfred{
127074462Salfred	if (debug_level)
127174462Salfred		log_from_addr("nlm4_granted_res", rqstp);
127274462Salfred	return (NULL);
127374462Salfred}
127474462Salfred
127574462Salfred/* ------------------------------------------------------------------------- */
127674462Salfred/*
127774462Salfred * Calls for PCNFS locking (aka non-monitored locking, no involvement
127874462Salfred * of rpc.statd).
127974462Salfred *
128074462Salfred * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
128174462Salfred */
128274462Salfred
128374462Salfred/* nlm_share --------------------------------------------------------------- */
128474462Salfred/*
128574462Salfred * Purpose:	Establish a DOS-style lock
128674462Salfred * Returns:	success or failure
128774462Salfred * Notes:	Blocking locks are not supported - client is expected
128874462Salfred *		to retry if required.
128974462Salfred */
129074462Salfrednlm4_shareres *
129174462Salfrednlm4_share_4_svc(arg, rqstp)
129274462Salfred	nlm4_shareargs *arg;
129374462Salfred	struct svc_req *rqstp;
129474462Salfred{
129574462Salfred	static nlm4_shareres res;
129674462Salfred
129774462Salfred	if (debug_level)
129874462Salfred		log_from_addr("nlm4_share", rqstp);
129974462Salfred
130074462Salfred	res.cookie = arg->cookie;
130174462Salfred	res.stat = nlm4_granted;
130274462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
130374462Salfred	return (&res);
130474462Salfred}
130574462Salfred
130674462Salfred/* nlm4_unshare ------------------------------------------------------------ */
130774462Salfred/*
130874462Salfred * Purpose:	Release a DOS-style lock
130974462Salfred * Returns:	nlm_granted, unless in grace period
131074462Salfred * Notes:
131174462Salfred */
131274462Salfrednlm4_shareres *
131374462Salfrednlm4_unshare_4_svc(arg, rqstp)
131474462Salfred	nlm4_shareargs *arg;
131574462Salfred	struct svc_req *rqstp;
131674462Salfred{
131774462Salfred	static nlm4_shareres res;
131874462Salfred
131974462Salfred	if (debug_level)
132074462Salfred		log_from_addr("nlm_unshare", rqstp);
132174462Salfred
132274462Salfred	res.cookie = arg->cookie;
132374462Salfred	res.stat = nlm4_granted;
132474462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
132574462Salfred	return (&res);
132674462Salfred}
132774462Salfred
132874462Salfred/* nlm4_nm_lock ------------------------------------------------------------ */
132974462Salfred/*
133074462Salfred * Purpose:	non-monitored version of nlm4_lock()
133174462Salfred * Returns:	as for nlm4_lock()
133274462Salfred * Notes:	These locks are in the same style as the standard nlm4_lock,
133374462Salfred *		but the rpc.statd should not be called to establish a
133474462Salfred *		monitor for the client machine, since that machine is
133574462Salfred *		declared not to be running a rpc.statd, and so would not
133674462Salfred *		respond to the statd protocol.
133774462Salfred */
133874462Salfrednlm4_res *
133974462Salfrednlm4_nm_lock_4_svc(arg, rqstp)
134074462Salfred	nlm4_lockargs *arg;
134174462Salfred	struct svc_req *rqstp;
134274462Salfred{
134374462Salfred	static nlm4_res res;
134474462Salfred
134574462Salfred	if (debug_level)
134674462Salfred		log_from_addr("nlm4_nm_lock", rqstp);
134774462Salfred
134874462Salfred	/* copy cookie from arg to result.  See comment in nlm4_test_1() */
134974462Salfred	res.cookie = arg->cookie;
135074462Salfred	res.stat.stat = nlm4_granted;
135174462Salfred	return (&res);
135274462Salfred}
135374462Salfred
135474462Salfred/* nlm4_free_all ------------------------------------------------------------ */
135574462Salfred/*
135674462Salfred * Purpose:	Release all locks held by a named client
135774462Salfred * Returns:	Nothing
135874462Salfred * Notes:	Potential denial of service security problem here - the
135974462Salfred *		locks to be released are specified by a host name, independent
136074462Salfred *		of the address from which the request has arrived.
136174462Salfred *		Should probably be rejected if the named host has been
136274462Salfred *		using monitored locks.
136374462Salfred */
136474462Salfredvoid *
136574462Salfrednlm4_free_all_4_svc(arg, rqstp)
136675631Salfred	struct nlm4_notify *arg;
136774462Salfred	struct svc_req *rqstp;
136874462Salfred{
136974462Salfred	static char dummy;
137074462Salfred
137174462Salfred	if (debug_level)
137274462Salfred		log_from_addr("nlm4_free_all", rqstp);
137374462Salfred	return (&dummy);
137474462Salfred}
137574462Salfred
137674462Salfred/* nlm_sm_notify --------------------------------------------------------- */
137774462Salfred/*
137874462Salfred * Purpose:	called by rpc.statd when a monitored host state changes.
137974462Salfred * Returns:	Nothing
138074462Salfred */
138174462Salfredvoid *
138274462Salfrednlm_sm_notify_0_svc(arg, rqstp)
138374462Salfred	struct nlm_sm_status *arg;
138474462Salfred	struct svc_req *rqstp;
138574462Salfred{
138674462Salfred	static char dummy;
138774462Salfred	notify(arg->mon_name, arg->state);
138874462Salfred	return (&dummy);
138974462Salfred}
1390