174462Salfred/*	$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $	*/
274462Salfred/*	$FreeBSD: releng/11.0/usr.sbin/rpc.lockd/lock_proc.c 299986 2016-05-16 23:00:48Z truckman $ */
374462Salfred/*
474462Salfred * Copyright (c) 1995
574462Salfred *	A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
674462Salfred *
774462Salfred * Redistribution and use in source and binary forms, with or without
874462Salfred * modification, are permitted provided that the following conditions
974462Salfred * are met:
1074462Salfred * 1. Redistributions of source code must retain the above copyright
1174462Salfred *    notice, this list of conditions and the following disclaimer.
1274462Salfred * 2. Redistributions in binary form must reproduce the above copyright
1374462Salfred *    notice, this list of conditions and the following disclaimer in the
1474462Salfred *    documentation and/or other materials provided with the distribution.
1574462Salfred * 3. All advertising materials mentioning features or use of this software
1674462Salfred *    must display the following acknowledgement:
1774462Salfred *	This product includes software developed for the FreeBSD project
1874462Salfred * 4. Neither the name of the author nor the names of any co-contributors
1974462Salfred *    may be used to endorse or promote products derived from this software
2074462Salfred *    without specific prior written permission.
2174462Salfred *
2274462Salfred * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
2374462Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2474462Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2574462Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2674462Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2774462Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2874462Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2974462Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3074462Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3174462Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3274462Salfred * SUCH DAMAGE.
3374462Salfred *
3474462Salfred */
3574462Salfred
3674462Salfred#include <sys/cdefs.h>
3774462Salfred#ifndef lint
3874462Salfred__RCSID("$NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $");
3974462Salfred#endif
4074462Salfred
4174462Salfred#include <sys/param.h>
4274462Salfred#include <sys/socket.h>
4374462Salfred
4474462Salfred#include <netinet/in.h>
4574462Salfred#include <arpa/inet.h>
4674462Salfred
4774462Salfred#include <netdb.h>
4874462Salfred#include <stdio.h>
4974462Salfred#include <string.h>
5074462Salfred#include <syslog.h>
51136320Sstefanf#include <unistd.h>
5274462Salfred#include <netconfig.h>
5374462Salfred
5474462Salfred#include <rpc/rpc.h>
5574462Salfred#include <rpcsvc/sm_inter.h>
5674462Salfred
5774462Salfred#include "lockd.h"
5874462Salfred#include <rpcsvc/nlm_prot.h>
5974462Salfred#include "lockd_lock.h"
6074462Salfred
6174462Salfred
6274462Salfred#define	CLIENT_CACHE_SIZE	64	/* No. of client sockets cached */
6374462Salfred#define	CLIENT_CACHE_LIFETIME	120	/* In seconds */
6474462Salfred
65141217Skuriyama#define	getrpcaddr(rqstp)	(struct sockaddr *)(svc_getrpccaller((rqstp)->rq_xprt)->buf)
66141217Skuriyama
6792969Salfredstatic void	log_from_addr(const char *, struct svc_req *);
6892909Salfredstatic void	log_netobj(netobj *obj);
6992909Salfredstatic int	addrcmp(struct sockaddr *, struct sockaddr *);
7074462Salfred
7174462Salfred/* log_from_addr ----------------------------------------------------------- */
7274462Salfred/*
7374462Salfred * Purpose:	Log name of function called and source address
7474462Salfred * Returns:	Nothing
7574462Salfred * Notes:	Extracts the source address from the transport handle
7674462Salfred *		passed in as part of the called procedure specification
7774462Salfred */
7874462Salfredstatic void
79260250Sdelphijlog_from_addr(const char *fun_name, struct svc_req *req)
8074462Salfred{
8174462Salfred	struct sockaddr *addr;
8274462Salfred	char hostname_buf[NI_MAXHOST];
8374462Salfred
8474462Salfred	addr = svc_getrpccaller(req->rq_xprt)->buf;
8574462Salfred	if (getnameinfo(addr , addr->sa_len, hostname_buf, sizeof hostname_buf,
8674462Salfred	    NULL, 0, 0) != 0)
8774462Salfred		return;
8874462Salfred
8974462Salfred	syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
9074462Salfred}
9174462Salfred
9284923Salfred/* log_netobj ----------------------------------------------------------- */
9384923Salfred/*
9484923Salfred * Purpose:	Log a netobj
9584923Salfred * Returns:	Nothing
9684923Salfred * Notes:	This function should only really be called as part of
9784923Salfred *  		a debug subsystem.
9884923Salfred*/
9984923Salfredstatic void
100260250Sdelphijlog_netobj(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);
115299986Struckman	for (i=0, tmp1 = objvalbuffer, tmp2 = objascbuffer; i < maxlen;
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
161260250Sdelphijaddrcmp(struct sockaddr *sa1, struct sockaddr *sa2)
16274462Salfred{
16374462Salfred	int len;
16474462Salfred	void *p1, *p2;
16574462Salfred
16674462Salfred	if (sa1->sa_family != sa2->sa_family)
16774462Salfred		return -1;
16874462Salfred
16974462Salfred	switch (sa1->sa_family) {
17074462Salfred	case AF_INET:
17174462Salfred		p1 = &((struct sockaddr_in *)sa1)->sin_addr;
17274462Salfred		p2 = &((struct sockaddr_in *)sa2)->sin_addr;
17374462Salfred		len = 4;
17474462Salfred		break;
17574462Salfred	case AF_INET6:
17674462Salfred		p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
17774462Salfred		p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
17874462Salfred		len = 16;
17974462Salfred		break;
18074462Salfred	default:
18174462Salfred		return -1;
18274462Salfred	}
18374462Salfred
18474462Salfred	return memcmp(p1, p2, len);
18574462Salfred}
18674462Salfred
18774462SalfredCLIENT *
188260250Sdelphijget_client(struct sockaddr *host_addr, rpcvers_t vers)
18974462Salfred{
19074462Salfred	CLIENT *client;
19174462Salfred	struct timeval retry_time, time_now;
192141217Skuriyama	int error, i;
19392977Salfred	const char *netid;
19474462Salfred	struct netconfig *nconf;
19574462Salfred	char host[NI_MAXHOST];
196126606Sroam	uid_t old_euid;
197126606Sroam	int clnt_fd;
19874462Salfred
19974462Salfred	gettimeofday(&time_now, NULL);
20074462Salfred
20174462Salfred	/*
20274462Salfred	 * Search for the given client in the cache, zapping any expired
20374462Salfred	 * entries that we happen to notice in passing.
20474462Salfred	 */
20574462Salfred	for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
20674462Salfred		client = clnt_cache_ptr[i];
20774462Salfred		if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
20874462Salfred		    < time_now.tv_sec)) {
20974462Salfred			/* Cache entry has expired. */
21074462Salfred			if (debug_level > 3)
21174462Salfred				syslog(LOG_DEBUG, "Expired CLIENT* in cache");
21274462Salfred			clnt_cache_time[i] = 0L;
21374462Salfred			clnt_destroy(client);
21474462Salfred			clnt_cache_ptr[i] = NULL;
21574462Salfred			client = NULL;
21674462Salfred		}
21774462Salfred		if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i],
21876093Salfred		    host_addr) && clnt_cache_vers[i] == vers) {
21974462Salfred			/* Found it! */
22074462Salfred			if (debug_level > 3)
22174462Salfred				syslog(LOG_DEBUG, "Found CLIENT* in cache");
22274462Salfred			return (client);
22374462Salfred		}
22474462Salfred	}
22574462Salfred
22676093Salfred	if (debug_level > 3)
22776093Salfred		syslog(LOG_DEBUG, "CLIENT* not found in cache, creating");
22876093Salfred
22974462Salfred	/* Not found in cache.  Free the next entry if it is in use. */
23074462Salfred	if (clnt_cache_ptr[clnt_cache_next_to_use]) {
23174462Salfred		clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
23274462Salfred		clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
23374462Salfred	}
23474462Salfred
23574462Salfred	/*
23674462Salfred	 * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
23774462Salfred	 * to avoid DNS lookups.
23874462Salfred	 */
239141217Skuriyama	error = getnameinfo(host_addr, host_addr->sa_len, host, sizeof host,
240141217Skuriyama			    NULL, 0, NI_NUMERICHOST);
241141217Skuriyama	if (error != 0) {
242141217Skuriyama		syslog(LOG_ERR, "unable to get name string for caller: %s",
243141217Skuriyama		       gai_strerror(error));
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
274126606Sroam	/* Get the FD of the client, for bindresvport. */
275126606Sroam	clnt_control(client, CLGET_FD, &clnt_fd);
276126606Sroam
277126606Sroam	/* Regain root privileges, for bindresvport. */
278126606Sroam	old_euid = geteuid();
279126606Sroam	seteuid(0);
280126606Sroam
281126606Sroam	/*
282126606Sroam	 * Bind the client FD to a reserved port.
283126606Sroam	 * Some NFS servers reject any NLM request from a non-reserved port.
284126606Sroam	 */
285126606Sroam	bindresvport(clnt_fd, NULL);
286126606Sroam
287126606Sroam	/* Drop root privileges again. */
288126606Sroam	seteuid(old_euid);
289126606Sroam
29074462Salfred	/* Success - update the cache entry */
29174462Salfred	clnt_cache_ptr[clnt_cache_next_to_use] = client;
29274462Salfred	memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
29374462Salfred	    host_addr->sa_len);
29476093Salfred	clnt_cache_vers[clnt_cache_next_to_use] = vers;
29574462Salfred	clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
296132254Smr	if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE)
29774462Salfred		clnt_cache_next_to_use = 0;
29874462Salfred
29974462Salfred	/*
30074462Salfred	 * Disable the default timeout, so we can specify our own in calls
30174462Salfred	 * to clnt_call().  (Note that the timeout is a different concept
30274462Salfred	 * from the retry period set in clnt_udp_create() above.)
30374462Salfred	 */
30474462Salfred	retry_time.tv_sec = -1;
30574462Salfred	retry_time.tv_usec = -1;
30674462Salfred	clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
30774462Salfred
30874462Salfred	if (debug_level > 3)
30974462Salfred		syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
31074462Salfred	return client;
31174462Salfred}
31274462Salfred
31374462Salfred
31474462Salfred/* transmit_result --------------------------------------------------------- */
31574462Salfred/*
31674462Salfred * Purpose:	Transmit result for nlm_xxx_msg pseudo-RPCs
31774462Salfred * Returns:	Nothing - we have no idea if the datagram got there
31874462Salfred * Notes:	clnt_call() will always fail (with timeout) as we are
31974462Salfred *		calling it with timeout 0 as a hack to just issue a datagram
32074462Salfred *		without expecting a result
32174462Salfred */
32274462Salfredvoid
323260250Sdelphijtransmit_result(int opcode, nlm_res *result, struct sockaddr *addr)
32474462Salfred{
32574462Salfred	static char dummy;
32674462Salfred	CLIENT *cli;
32774462Salfred	struct timeval timeo;
32874462Salfred	int success;
32974462Salfred
33074462Salfred	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
33174462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
33274462Salfred		timeo.tv_usec = 0;
33374462Salfred
334121558Speter		success = clnt_call(cli, opcode, (xdrproc_t)xdr_nlm_res, result,
335121558Speter		    (xdrproc_t)xdr_void, &dummy, timeo);
33674462Salfred
33774462Salfred		if (debug_level > 2)
33874462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
33974462Salfred			    success, clnt_sperrno(success));
34074462Salfred	}
34174462Salfred}
34274462Salfred/* transmit4_result --------------------------------------------------------- */
34374462Salfred/*
34474462Salfred * Purpose:	Transmit result for nlm4_xxx_msg pseudo-RPCs
34574462Salfred * Returns:	Nothing - we have no idea if the datagram got there
34674462Salfred * Notes:	clnt_call() will always fail (with timeout) as we are
34774462Salfred *		calling it with timeout 0 as a hack to just issue a datagram
34874462Salfred *		without expecting a result
34974462Salfred */
35074462Salfredvoid
351260250Sdelphijtransmit4_result(int opcode, nlm4_res *result, struct sockaddr *addr)
35274462Salfred{
35374462Salfred	static char dummy;
35474462Salfred	CLIENT *cli;
35574462Salfred	struct timeval timeo;
35674462Salfred	int success;
35774462Salfred
35874462Salfred	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
35974462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
36074462Salfred		timeo.tv_usec = 0;
36174462Salfred
362121558Speter		success = clnt_call(cli, opcode,
363121558Speter		    (xdrproc_t)xdr_nlm4_res, result,
364121558Speter		    (xdrproc_t)xdr_void, &dummy, timeo);
36574462Salfred
36674462Salfred		if (debug_level > 2)
36774462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
36874462Salfred			    success, clnt_sperrno(success));
36974462Salfred	}
37074462Salfred}
37174462Salfred
37274462Salfred/*
37374462Salfred * converts a struct nlm_lock to struct nlm4_lock
37474462Salfred */
37574462Salfredstatic void
376260250Sdelphijnlmtonlm4(struct nlm_lock *arg, struct nlm4_lock *arg4)
37774462Salfred{
378132254Smr	arg4->caller_name = arg->caller_name;
379132254Smr	arg4->fh = arg->fh;
380132254Smr	arg4->oh = arg->oh;
381132254Smr	arg4->svid = arg->svid;
38274462Salfred	arg4->l_offset = arg->l_offset;
38374462Salfred	arg4->l_len = arg->l_len;
38474462Salfred}
38574462Salfred/* ------------------------------------------------------------------------- */
38674462Salfred/*
38774462Salfred * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
38874462Salfred * involved to ensure reclaim of locks after a crash of the "stateless"
38974462Salfred * server.
39074462Salfred *
39174462Salfred * These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
39274462Salfred * The first are standard RPCs with argument and result.
39374462Salfred * The nlm_xxx_msg() calls implement exactly the same functions, but
39474462Salfred * use two pseudo-RPCs (one in each direction).  These calls are NOT
39574462Salfred * standard use of the RPC protocol in that they do not return a result
39674462Salfred * at all (NB. this is quite different from returning a void result).
39774462Salfred * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
39874462Salfred * datagrams, requiring higher-level code to perform retries.
39974462Salfred *
40074462Salfred * Despite the disadvantages of the nlm_xxx_msg() approach (some of which
40174462Salfred * are documented in the comments to get_client() above), this is the
40274462Salfred * interface used by all current commercial NFS implementations
40374462Salfred * [Solaris, SCO, AIX etc.].  This is presumed to be because these allow
40474462Salfred * implementations to continue using the standard RPC libraries, while
40574462Salfred * avoiding the block-until-result nature of the library interface.
40674462Salfred *
40774462Salfred * No client implementations have been identified so far that make use
40874462Salfred * of the true RPC version (early SunOS releases would be a likely candidate
40974462Salfred * for testing).
41074462Salfred */
41174462Salfred
41274462Salfred/* nlm_test ---------------------------------------------------------------- */
41374462Salfred/*
41474462Salfred * Purpose:	Test whether a specified lock would be granted if requested
41574462Salfred * Returns:	nlm_granted (or error code)
41674462Salfred * Notes:
41774462Salfred */
41874462Salfrednlm_testres *
419260250Sdelphijnlm_test_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
42074462Salfred{
42174462Salfred	static nlm_testres res;
42274462Salfred	struct nlm4_lock arg4;
42374462Salfred	struct nlm4_holder *holder;
42474462Salfred	nlmtonlm4(&arg->alock, &arg4);
42574462Salfred
42674462Salfred	if (debug_level)
42774462Salfred		log_from_addr("nlm_test", rqstp);
42874462Salfred
42984923Salfred	holder = testlock(&arg4, arg->exclusive, 0);
43074462Salfred	/*
43174462Salfred	 * Copy the cookie from the argument into the result.  Note that this
43274462Salfred	 * is slightly hazardous, as the structure contains a pointer to a
43374462Salfred	 * malloc()ed buffer that will get freed by the caller.  However, the
43474462Salfred	 * main function transmits the result before freeing the argument
43574462Salfred	 * so it is in fact safe.
43674462Salfred	 */
43774462Salfred	res.cookie = arg->cookie;
43874462Salfred	if (holder == NULL) {
43974462Salfred		res.stat.stat = nlm_granted;
44074462Salfred	} else {
44174462Salfred		res.stat.stat = nlm_denied;
44274462Salfred		memcpy(&res.stat.nlm_testrply_u.holder, holder,
44374462Salfred		    sizeof(struct nlm_holder));
44474462Salfred		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
44574462Salfred		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
44674462Salfred	}
44774462Salfred	return (&res);
44874462Salfred}
44974462Salfred
45074462Salfredvoid *
451260250Sdelphijnlm_test_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
45274462Salfred{
45374462Salfred	nlm_testres res;
45474462Salfred	static char dummy;
45574462Salfred	struct sockaddr *addr;
45674462Salfred	CLIENT *cli;
45774462Salfred	int success;
45874462Salfred	struct timeval timeo;
45974462Salfred	struct nlm4_lock arg4;
46074462Salfred	struct nlm4_holder *holder;
46174462Salfred
46274462Salfred	nlmtonlm4(&arg->alock, &arg4);
46374462Salfred
46474462Salfred	if (debug_level)
46574462Salfred		log_from_addr("nlm_test_msg", rqstp);
46674462Salfred
46784923Salfred	holder = testlock(&arg4, arg->exclusive, 0);
46874462Salfred
46974462Salfred	res.cookie = arg->cookie;
47074462Salfred	if (holder == NULL) {
47174462Salfred		res.stat.stat = nlm_granted;
47274462Salfred	} else {
47374462Salfred		res.stat.stat = nlm_denied;
47474462Salfred		memcpy(&res.stat.nlm_testrply_u.holder, holder,
47574462Salfred		    sizeof(struct nlm_holder));
47674462Salfred		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
47774462Salfred		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
47874462Salfred	}
47974462Salfred
48074462Salfred	/*
48174462Salfred	 * nlm_test has different result type to the other operations, so
48274462Salfred	 * can't use transmit_result() in this case
48374462Salfred	 */
48474462Salfred	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
48574462Salfred	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
48674462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
48774462Salfred		timeo.tv_usec = 0;
48874462Salfred
489121558Speter		success = clnt_call(cli, NLM_TEST_RES,
490121558Speter		    (xdrproc_t)xdr_nlm_testres, &res,
491121558Speter		    (xdrproc_t)xdr_void, &dummy, timeo);
49274462Salfred
49374462Salfred		if (debug_level > 2)
49474462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d", success);
49574462Salfred	}
49674462Salfred	return (NULL);
49774462Salfred}
49874462Salfred
49974462Salfred/* nlm_lock ---------------------------------------------------------------- */
50074462Salfred/*
50174462Salfred * Purposes:	Establish a lock
50274462Salfred * Returns:	granted, denied or blocked
50374462Salfred * Notes:	*** grace period support missing
50474462Salfred */
50574462Salfrednlm_res *
506260250Sdelphijnlm_lock_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
50774462Salfred{
50874462Salfred	static nlm_res res;
50974462Salfred	struct nlm4_lockargs arg4;
51074462Salfred	nlmtonlm4(&arg->alock, &arg4.alock);
51174462Salfred	arg4.cookie = arg->cookie;
51274462Salfred	arg4.block = arg->block;
51374462Salfred	arg4.exclusive = arg->exclusive;
51474462Salfred	arg4.reclaim = arg->reclaim;
51574462Salfred	arg4.state = arg->state;
51674462Salfred
51774462Salfred	if (debug_level)
51874462Salfred		log_from_addr("nlm_lock", rqstp);
51974462Salfred
52074462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
52174462Salfred	res.cookie = arg->cookie;
52274462Salfred
52374462Salfred	res.stat.stat = getlock(&arg4, rqstp, LOCK_MON);
52474462Salfred	return (&res);
52574462Salfred}
52674462Salfred
52774462Salfredvoid *
528260250Sdelphijnlm_lock_msg_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
52974462Salfred{
53074462Salfred	static nlm_res res;
53174462Salfred	struct nlm4_lockargs arg4;
53274462Salfred
53374462Salfred	nlmtonlm4(&arg->alock, &arg4.alock);
53474462Salfred	arg4.cookie = arg->cookie;
53574462Salfred	arg4.block = arg->block;
53674462Salfred	arg4.exclusive = arg->exclusive;
53774462Salfred	arg4.reclaim = arg->reclaim;
53874462Salfred	arg4.state = arg->state;
53974462Salfred
54074462Salfred	if (debug_level)
54174462Salfred		log_from_addr("nlm_lock_msg", rqstp);
54274462Salfred
54374462Salfred	res.cookie = arg->cookie;
54474462Salfred	res.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON);
545141217Skuriyama	transmit_result(NLM_LOCK_RES, &res, getrpcaddr(rqstp));
54674462Salfred
54774462Salfred	return (NULL);
54874462Salfred}
54974462Salfred
55074462Salfred/* nlm_cancel -------------------------------------------------------------- */
55174462Salfred/*
55274462Salfred * Purpose:	Cancel a blocked lock request
55374462Salfred * Returns:	granted or denied
55474462Salfred * Notes:
55574462Salfred */
55674462Salfrednlm_res *
557260250Sdelphijnlm_cancel_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
55874462Salfred{
55974462Salfred	static nlm_res res;
56074462Salfred	struct nlm4_lock arg4;
56174462Salfred
56274462Salfred	nlmtonlm4(&arg->alock, &arg4);
56374462Salfred
56474462Salfred	if (debug_level)
56574462Salfred		log_from_addr("nlm_cancel", rqstp);
56674462Salfred
56774462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
56874462Salfred	res.cookie = arg->cookie;
56974462Salfred
57074462Salfred	/*
57174462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
57274462Salfred	 * a lock to cancel, so this call always fails.
57374462Salfred	 */
57474462Salfred	res.stat.stat = unlock(&arg4, LOCK_CANCEL);
57574462Salfred	return (&res);
57674462Salfred}
57774462Salfred
57874462Salfredvoid *
579260250Sdelphijnlm_cancel_msg_1_svc(nlm_cancargs *arg, 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);
595141217Skuriyama	transmit_result(NLM_CANCEL_RES, &res, getrpcaddr(rqstp));
59674462Salfred	return (NULL);
59774462Salfred}
59874462Salfred
59974462Salfred/* nlm_unlock -------------------------------------------------------------- */
60074462Salfred/*
60174462Salfred * Purpose:	Release an existing lock
60274462Salfred * Returns:	Always granted, unless during grace period
60374462Salfred * Notes:	"no such lock" error condition is ignored, as the
60474462Salfred *		protocol uses unreliable UDP datagrams, and may well
60574462Salfred *		re-try an unlock that has already succeeded.
60674462Salfred */
60774462Salfrednlm_res *
608260250Sdelphijnlm_unlock_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
60974462Salfred{
61074462Salfred	static nlm_res res;
61174462Salfred	struct nlm4_lock arg4;
61274462Salfred
61374462Salfred	nlmtonlm4(&arg->alock, &arg4);
61474462Salfred
61574462Salfred	if (debug_level)
61674462Salfred		log_from_addr("nlm_unlock", rqstp);
61774462Salfred
61874462Salfred	res.stat.stat = unlock(&arg4, 0);
61974462Salfred	res.cookie = arg->cookie;
62074462Salfred
62174462Salfred	return (&res);
62274462Salfred}
62374462Salfred
62474462Salfredvoid *
625260250Sdelphijnlm_unlock_msg_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
62674462Salfred{
62774462Salfred	static nlm_res res;
62874462Salfred	struct nlm4_lock arg4;
62974462Salfred
63074462Salfred	nlmtonlm4(&arg->alock, &arg4);
63174462Salfred
63274462Salfred	if (debug_level)
63374462Salfred		log_from_addr("nlm_unlock_msg", rqstp);
63474462Salfred
63574462Salfred	res.stat.stat = unlock(&arg4, 0);
63674462Salfred	res.cookie = arg->cookie;
63774462Salfred
638141217Skuriyama	transmit_result(NLM_UNLOCK_RES, &res, getrpcaddr(rqstp));
63974462Salfred	return (NULL);
64074462Salfred}
64174462Salfred
64274462Salfred/* ------------------------------------------------------------------------- */
64374462Salfred/*
64474462Salfred * Client-side pseudo-RPCs for results.  Note that for the client there
64574462Salfred * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
64674462Salfred * version returns the results in the RPC result, and so the client
64774462Salfred * does not normally receive incoming RPCs.
64874462Salfred *
64974462Salfred * The exception to this is nlm_granted(), which is genuinely an RPC
65074462Salfred * call from the server to the client - a 'call-back' in normal procedure
65174462Salfred * call terms.
65274462Salfred */
65374462Salfred
65474462Salfred/* nlm_granted ------------------------------------------------------------- */
65574462Salfred/*
65674462Salfred * Purpose:	Receive notification that formerly blocked lock now granted
65774462Salfred * Returns:	always success ('granted')
65874462Salfred * Notes:
65974462Salfred */
66074462Salfrednlm_res *
661260250Sdelphijnlm_granted_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
66274462Salfred{
66374462Salfred	static nlm_res res;
66474462Salfred
66574462Salfred	if (debug_level)
66674462Salfred		log_from_addr("nlm_granted", rqstp);
66774462Salfred
66875631Salfred	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
66975631Salfred		nlm_granted, NULL, NLM_VERS) == 0 ?
67075631Salfred		nlm_granted : nlm_denied;
67175631Salfred
67274462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
67374462Salfred	res.cookie = arg->cookie;
67474462Salfred
67574462Salfred	return (&res);
67674462Salfred}
67774462Salfred
67874462Salfredvoid *
679260250Sdelphijnlm_granted_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
68074462Salfred{
68174462Salfred	static nlm_res res;
68274462Salfred
68374462Salfred	if (debug_level)
68474462Salfred		log_from_addr("nlm_granted_msg", rqstp);
68574462Salfred
68674462Salfred	res.cookie = arg->cookie;
687114993Srwatson	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
688114993Srwatson		nlm_granted, NULL, NLM_VERS) == 0 ?
689114993Srwatson		nlm_granted : nlm_denied;
690114993Srwatson
691141217Skuriyama	transmit_result(NLM_GRANTED_RES, &res, getrpcaddr(rqstp));
69274462Salfred	return (NULL);
69374462Salfred}
69474462Salfred
69574462Salfred/* nlm_test_res ------------------------------------------------------------ */
69674462Salfred/*
69774462Salfred * Purpose:	Accept result from earlier nlm_test_msg() call
69874462Salfred * Returns:	Nothing
69974462Salfred */
70074462Salfredvoid *
701260250Sdelphijnlm_test_res_1_svc(nlm_testres *arg, struct svc_req *rqstp)
70274462Salfred{
70374462Salfred	if (debug_level)
70474462Salfred		log_from_addr("nlm_test_res", rqstp);
70575631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat,
70675631Salfred		&arg->stat.nlm_testrply_u.holder.svid, NLM_VERS);
70774462Salfred	return (NULL);
70874462Salfred}
70974462Salfred
71074462Salfred/* nlm_lock_res ------------------------------------------------------------ */
71174462Salfred/*
71274462Salfred * Purpose:	Accept result from earlier nlm_lock_msg() call
71374462Salfred * Returns:	Nothing
71474462Salfred */
71574462Salfredvoid *
716260250Sdelphijnlm_lock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
71774462Salfred{
71874462Salfred	if (debug_level)
71974462Salfred		log_from_addr("nlm_lock_res", rqstp);
72074462Salfred
72175631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
72275631Salfred
72374462Salfred	return (NULL);
72474462Salfred}
72574462Salfred
72674462Salfred/* nlm_cancel_res ---------------------------------------------------------- */
72774462Salfred/*
72874462Salfred * Purpose:	Accept result from earlier nlm_cancel_msg() call
72974462Salfred * Returns:	Nothing
73074462Salfred */
73174462Salfredvoid *
732260250Sdelphijnlm_cancel_res_1_svc(nlm_res *arg __unused, struct svc_req *rqstp)
73374462Salfred{
73474462Salfred	if (debug_level)
73574462Salfred		log_from_addr("nlm_cancel_res", rqstp);
73674462Salfred	return (NULL);
73774462Salfred}
73874462Salfred
73974462Salfred/* nlm_unlock_res ---------------------------------------------------------- */
74074462Salfred/*
74174462Salfred * Purpose:	Accept result from earlier nlm_unlock_msg() call
74274462Salfred * Returns:	Nothing
74374462Salfred */
74474462Salfredvoid *
745260250Sdelphijnlm_unlock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
74674462Salfred{
74774462Salfred	if (debug_level)
74874462Salfred		log_from_addr("nlm_unlock_res", rqstp);
74975631Salfred
75086300Salfred	lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS);
75175631Salfred
75274462Salfred	return (NULL);
75374462Salfred}
75474462Salfred
75574462Salfred/* nlm_granted_res --------------------------------------------------------- */
75674462Salfred/*
75774462Salfred * Purpose:	Accept result from earlier nlm_granted_msg() call
75874462Salfred * Returns:	Nothing
75974462Salfred */
76074462Salfredvoid *
761260250Sdelphijnlm_granted_res_1_svc(nlm_res *arg __unused, struct svc_req *rqstp)
76274462Salfred{
76374462Salfred	if (debug_level)
76474462Salfred		log_from_addr("nlm_granted_res", rqstp);
76574462Salfred	return (NULL);
76674462Salfred}
76774462Salfred
76874462Salfred/* ------------------------------------------------------------------------- */
76974462Salfred/*
77074462Salfred * Calls for PCNFS locking (aka non-monitored locking, no involvement
77174462Salfred * of rpc.statd).
77274462Salfred *
77374462Salfred * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
77474462Salfred */
77574462Salfred
77674462Salfred/* nlm_share --------------------------------------------------------------- */
77774462Salfred/*
77874462Salfred * Purpose:	Establish a DOS-style lock
77974462Salfred * Returns:	success or failure
78074462Salfred * Notes:	Blocking locks are not supported - client is expected
78174462Salfred *		to retry if required.
78274462Salfred */
78374462Salfrednlm_shareres *
784260250Sdelphijnlm_share_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
78574462Salfred{
78674462Salfred	static nlm_shareres res;
78774462Salfred
78874462Salfred	if (debug_level)
78974462Salfred		log_from_addr("nlm_share", rqstp);
79074462Salfred
79174462Salfred	res.cookie = arg->cookie;
79274462Salfred	res.stat = nlm_granted;
79374462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
79474462Salfred	return (&res);
79574462Salfred}
79674462Salfred
79774462Salfred/* nlm_unshare ------------------------------------------------------------ */
79874462Salfred/*
79974462Salfred * Purpose:	Release a DOS-style lock
80074462Salfred * Returns:	nlm_granted, unless in grace period
80174462Salfred * Notes:
80274462Salfred */
80374462Salfrednlm_shareres *
804260250Sdelphijnlm_unshare_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
80574462Salfred{
80674462Salfred	static nlm_shareres res;
80774462Salfred
80874462Salfred	if (debug_level)
80974462Salfred		log_from_addr("nlm_unshare", 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_nm_lock ------------------------------------------------------------ */
81874462Salfred/*
81974462Salfred * Purpose:	non-monitored version of nlm_lock()
82074462Salfred * Returns:	as for nlm_lock()
82174462Salfred * Notes:	These locks are in the same style as the standard nlm_lock,
82274462Salfred *		but the rpc.statd should not be called to establish a
82374462Salfred *		monitor for the client machine, since that machine is
82474462Salfred *		declared not to be running a rpc.statd, and so would not
82574462Salfred *		respond to the statd protocol.
82674462Salfred */
82774462Salfrednlm_res *
828260250Sdelphijnlm_nm_lock_3_svc(nlm_lockargs *arg, struct svc_req *rqstp)
82974462Salfred{
83074462Salfred	static nlm_res res;
83174462Salfred
83274462Salfred	if (debug_level)
83374462Salfred		log_from_addr("nlm_nm_lock", rqstp);
83474462Salfred
83574462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
83674462Salfred	res.cookie = arg->cookie;
83774462Salfred	res.stat.stat = nlm_granted;
83874462Salfred	return (&res);
83974462Salfred}
84074462Salfred
84174462Salfred/* nlm_free_all ------------------------------------------------------------ */
84274462Salfred/*
84374462Salfred * Purpose:	Release all locks held by a named client
84474462Salfred * Returns:	Nothing
84574462Salfred * Notes:	Potential denial of service security problem here - the
84674462Salfred *		locks to be released are specified by a host name, independent
84774462Salfred *		of the address from which the request has arrived.
84874462Salfred *		Should probably be rejected if the named host has been
84974462Salfred *		using monitored locks.
85074462Salfred */
85174462Salfredvoid *
852260250Sdelphijnlm_free_all_3_svc(nlm_notify *arg __unused, struct svc_req *rqstp)
85374462Salfred{
85474462Salfred	static char dummy;
85574462Salfred
85674462Salfred	if (debug_level)
85774462Salfred		log_from_addr("nlm_free_all", rqstp);
85874462Salfred	return (&dummy);
85974462Salfred}
86074462Salfred
86174462Salfred/* calls for nlm version 4 (NFSv3) */
86274462Salfred/* nlm_test ---------------------------------------------------------------- */
86374462Salfred/*
86474462Salfred * Purpose:	Test whether a specified lock would be granted if requested
86574462Salfred * Returns:	nlm_granted (or error code)
86674462Salfred * Notes:
86774462Salfred */
86874462Salfrednlm4_testres *
869260250Sdelphijnlm4_test_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
87074462Salfred{
87174462Salfred	static nlm4_testres res;
87274462Salfred	struct nlm4_holder *holder;
87374462Salfred
87474462Salfred	if (debug_level)
87574462Salfred		log_from_addr("nlm4_test", rqstp);
87684923Salfred	if (debug_level > 5) {
87784923Salfred		syslog(LOG_DEBUG, "Locking arguments:\n");
87884923Salfred		log_netobj(&(arg->cookie));
87984923Salfred		syslog(LOG_DEBUG, "Alock arguments:\n");
88084923Salfred		syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
88184923Salfred		syslog(LOG_DEBUG, "File Handle:\n");
88284923Salfred		log_netobj(&(arg->alock.fh));
88384923Salfred		syslog(LOG_DEBUG, "Owner Handle:\n");
88484923Salfred		log_netobj(&(arg->alock.oh));
88584923Salfred		syslog(LOG_DEBUG, "SVID:        %d\n", arg->alock.svid);
88686319Salfred		syslog(LOG_DEBUG, "Lock Offset: %llu\n",
88786319Salfred		    (unsigned long long)arg->alock.l_offset);
88886319Salfred		syslog(LOG_DEBUG, "Lock Length: %llu\n",
88986319Salfred		    (unsigned long long)arg->alock.l_len);
89084923Salfred		syslog(LOG_DEBUG, "Exclusive:   %s\n",
89184923Salfred		    (arg->exclusive ? "true" : "false"));
89284923Salfred	}
89374462Salfred
89484923Salfred	holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
89574462Salfred
89674462Salfred	/*
89774462Salfred	 * Copy the cookie from the argument into the result.  Note that this
89874462Salfred	 * is slightly hazardous, as the structure contains a pointer to a
89974462Salfred	 * malloc()ed buffer that will get freed by the caller.  However, the
90074462Salfred	 * main function transmits the result before freeing the argument
90174462Salfred	 * so it is in fact safe.
90274462Salfred	 */
90374462Salfred	res.cookie = arg->cookie;
90474462Salfred	if (holder == NULL) {
90574462Salfred		res.stat.stat = nlm4_granted;
90674462Salfred	} else {
90774462Salfred		res.stat.stat = nlm4_denied;
90874462Salfred		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
90974462Salfred		    sizeof(struct nlm4_holder));
91074462Salfred	}
91174462Salfred	return (&res);
91274462Salfred}
91374462Salfred
91474462Salfredvoid *
915260250Sdelphijnlm4_test_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
91674462Salfred{
91774462Salfred	nlm4_testres res;
91874462Salfred	static char dummy;
91974462Salfred	struct sockaddr *addr;
92074462Salfred	CLIENT *cli;
92174462Salfred	int success;
92274462Salfred	struct timeval timeo;
92374462Salfred	struct nlm4_holder *holder;
92474462Salfred
92574462Salfred	if (debug_level)
92674462Salfred		log_from_addr("nlm4_test_msg", rqstp);
92774462Salfred
92884923Salfred	holder = testlock(&arg->alock, arg->exclusive, LOCK_V4);
92974462Salfred
93074462Salfred	res.cookie = arg->cookie;
93174462Salfred	if (holder == NULL) {
93274462Salfred		res.stat.stat = nlm4_granted;
93374462Salfred	} else {
93474462Salfred		res.stat.stat = nlm4_denied;
93574462Salfred		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
93674462Salfred		    sizeof(struct nlm4_holder));
93774462Salfred	}
93874462Salfred
93974462Salfred	/*
94074462Salfred	 * nlm_test has different result type to the other operations, so
94174462Salfred	 * can't use transmit4_result() in this case
94274462Salfred	 */
94374462Salfred	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
94474462Salfred	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
94574462Salfred		timeo.tv_sec = 0; /* No timeout - not expecting response */
94674462Salfred		timeo.tv_usec = 0;
94774462Salfred
948121558Speter		success = clnt_call(cli, NLM4_TEST_RES,
949121558Speter		    (xdrproc_t)xdr_nlm4_testres, &res,
950121558Speter		    (xdrproc_t)xdr_void, &dummy, timeo);
95174462Salfred
95274462Salfred		if (debug_level > 2)
95374462Salfred			syslog(LOG_DEBUG, "clnt_call returns %d", success);
95474462Salfred	}
95574462Salfred	return (NULL);
95674462Salfred}
95774462Salfred
95874462Salfred/* nlm_lock ---------------------------------------------------------------- */
95974462Salfred/*
96074462Salfred * Purposes:	Establish a lock
96174462Salfred * Returns:	granted, denied or blocked
96274462Salfred * Notes:	*** grace period support missing
96374462Salfred */
96474462Salfrednlm4_res *
965260250Sdelphijnlm4_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
96674462Salfred{
96774462Salfred	static nlm4_res res;
96874462Salfred
96974462Salfred	if (debug_level)
97074462Salfred		log_from_addr("nlm4_lock", rqstp);
97184923Salfred	if (debug_level > 5) {
97284923Salfred		syslog(LOG_DEBUG, "Locking arguments:\n");
97384923Salfred		log_netobj(&(arg->cookie));
97484923Salfred		syslog(LOG_DEBUG, "Alock arguments:\n");
97584923Salfred		syslog(LOG_DEBUG, "Caller Name: %s\n",arg->alock.caller_name);
97684923Salfred		syslog(LOG_DEBUG, "File Handle:\n");
97784923Salfred		log_netobj(&(arg->alock.fh));
97884923Salfred		syslog(LOG_DEBUG, "Owner Handle:\n");
97984923Salfred		log_netobj(&(arg->alock.oh));
98084923Salfred		syslog(LOG_DEBUG, "SVID:        %d\n", arg->alock.svid);
98186319Salfred		syslog(LOG_DEBUG, "Lock Offset: %llu\n",
98286319Salfred		    (unsigned long long)arg->alock.l_offset);
98386319Salfred		syslog(LOG_DEBUG, "Lock Length: %llu\n",
98486319Salfred		    (unsigned long long)arg->alock.l_len);
98584923Salfred		syslog(LOG_DEBUG, "Block:       %s\n", (arg->block ? "true" : "false"));
98684923Salfred		syslog(LOG_DEBUG, "Exclusive:   %s\n", (arg->exclusive ? "true" : "false"));
98784923Salfred		syslog(LOG_DEBUG, "Reclaim:     %s\n", (arg->reclaim ? "true" : "false"));
98884923Salfred		syslog(LOG_DEBUG, "State num:   %d\n", arg->state);
98984923Salfred	}
99074462Salfred
99174462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_4() */
99274462Salfred	res.cookie = arg->cookie;
99374462Salfred
99474462Salfred	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_V4);
99574462Salfred	return (&res);
99674462Salfred}
99774462Salfred
99874462Salfredvoid *
999260250Sdelphijnlm4_lock_msg_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
100074462Salfred{
100174462Salfred	static nlm4_res res;
100274462Salfred
100374462Salfred	if (debug_level)
100474462Salfred		log_from_addr("nlm4_lock_msg", rqstp);
100574462Salfred
100674462Salfred	res.cookie = arg->cookie;
100774462Salfred	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4);
1008141217Skuriyama	transmit4_result(NLM4_LOCK_RES, &res, getrpcaddr(rqstp));
100974462Salfred
101074462Salfred	return (NULL);
101174462Salfred}
101274462Salfred
101374462Salfred/* nlm_cancel -------------------------------------------------------------- */
101474462Salfred/*
101574462Salfred * Purpose:	Cancel a blocked lock request
101674462Salfred * Returns:	granted or denied
101774462Salfred * Notes:
101874462Salfred */
101974462Salfrednlm4_res *
1020260250Sdelphijnlm4_cancel_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
102174462Salfred{
102274462Salfred	static nlm4_res res;
102374462Salfred
102474462Salfred	if (debug_level)
102574462Salfred		log_from_addr("nlm4_cancel", rqstp);
102674462Salfred
102774462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
102874462Salfred	res.cookie = arg->cookie;
102974462Salfred
103074462Salfred	/*
103174462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
103274462Salfred	 * a lock to cancel, so this call always fails.
103374462Salfred	 */
103474462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL);
103574462Salfred	return (&res);
103674462Salfred}
103774462Salfred
103874462Salfredvoid *
1039260250Sdelphijnlm4_cancel_msg_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
104074462Salfred{
104174462Salfred	static nlm4_res res;
104274462Salfred
104374462Salfred	if (debug_level)
104474462Salfred		log_from_addr("nlm4_cancel_msg", rqstp);
104574462Salfred
104674462Salfred	res.cookie = arg->cookie;
104774462Salfred	/*
104874462Salfred	 * Since at present we never return 'nlm_blocked', there can never be
104974462Salfred	 * a lock to cancel, so this call always fails.
105074462Salfred	 */
105174462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4);
1052141217Skuriyama	transmit4_result(NLM4_CANCEL_RES, &res, getrpcaddr(rqstp));
105374462Salfred	return (NULL);
105474462Salfred}
105574462Salfred
105674462Salfred/* nlm_unlock -------------------------------------------------------------- */
105774462Salfred/*
105874462Salfred * Purpose:	Release an existing lock
105974462Salfred * Returns:	Always granted, unless during grace period
106074462Salfred * Notes:	"no such lock" error condition is ignored, as the
106174462Salfred *		protocol uses unreliable UDP datagrams, and may well
106274462Salfred *		re-try an unlock that has already succeeded.
106374462Salfred */
106474462Salfrednlm4_res *
1065260250Sdelphijnlm4_unlock_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
106674462Salfred{
106774462Salfred	static nlm4_res res;
106874462Salfred
106974462Salfred	if (debug_level)
107074462Salfred		log_from_addr("nlm4_unlock", rqstp);
107174462Salfred
107274462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_V4);
107374462Salfred	res.cookie = arg->cookie;
107474462Salfred
107574462Salfred	return (&res);
107674462Salfred}
107774462Salfred
107874462Salfredvoid *
1079260250Sdelphijnlm4_unlock_msg_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
108074462Salfred{
108174462Salfred	static nlm4_res res;
108274462Salfred
108374462Salfred	if (debug_level)
108474462Salfred		log_from_addr("nlm4_unlock_msg", rqstp);
108574462Salfred
108674462Salfred	res.stat.stat = unlock(&arg->alock, LOCK_V4);
108774462Salfred	res.cookie = arg->cookie;
108874462Salfred
1089141217Skuriyama	transmit4_result(NLM4_UNLOCK_RES, &res, getrpcaddr(rqstp));
109074462Salfred	return (NULL);
109174462Salfred}
109274462Salfred
109374462Salfred/* ------------------------------------------------------------------------- */
109474462Salfred/*
109574462Salfred * Client-side pseudo-RPCs for results.  Note that for the client there
109674462Salfred * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
109774462Salfred * version returns the results in the RPC result, and so the client
109874462Salfred * does not normally receive incoming RPCs.
109974462Salfred *
110074462Salfred * The exception to this is nlm_granted(), which is genuinely an RPC
110174462Salfred * call from the server to the client - a 'call-back' in normal procedure
110274462Salfred * call terms.
110374462Salfred */
110474462Salfred
110574462Salfred/* nlm_granted ------------------------------------------------------------- */
110674462Salfred/*
110774462Salfred * Purpose:	Receive notification that formerly blocked lock now granted
110874462Salfred * Returns:	always success ('granted')
110974462Salfred * Notes:
111074462Salfred */
111174462Salfrednlm4_res *
1112260250Sdelphijnlm4_granted_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
111374462Salfred{
111474462Salfred	static nlm4_res res;
111574462Salfred
111674462Salfred	if (debug_level)
111774462Salfred		log_from_addr("nlm4_granted", rqstp);
111874462Salfred
111975631Salfred	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
112075631Salfred		nlm4_granted, NULL, NLM_VERS4) == 0 ?
112175631Salfred		nlm4_granted : nlm4_denied;
112275631Salfred
112374462Salfred	/* copy cookie from arg to result.  See comment in nlm_test_1() */
112474462Salfred	res.cookie = arg->cookie;
112574462Salfred
112674462Salfred	return (&res);
112774462Salfred}
112874462Salfred
112974462Salfredvoid *
1130260250Sdelphijnlm4_granted_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
113174462Salfred{
113274462Salfred	static nlm4_res res;
113374462Salfred
113474462Salfred	if (debug_level)
113574462Salfred		log_from_addr("nlm4_granted_msg", rqstp);
113674462Salfred
113774462Salfred	res.cookie = arg->cookie;
1138114993Srwatson	res.stat.stat = lock_answer(arg->alock.svid, &arg->cookie,
1139114993Srwatson		nlm4_granted, NULL, NLM_VERS4) == 0 ?
1140114993Srwatson		nlm4_granted : nlm4_denied;
1141141217Skuriyama	transmit4_result(NLM4_GRANTED_RES, &res, getrpcaddr(rqstp));
114274462Salfred	return (NULL);
114374462Salfred}
114474462Salfred
114574462Salfred/* nlm_test_res ------------------------------------------------------------ */
114674462Salfred/*
114774462Salfred * Purpose:	Accept result from earlier nlm_test_msg() call
114874462Salfred * Returns:	Nothing
114974462Salfred */
115074462Salfredvoid *
1151260250Sdelphijnlm4_test_res_4_svc(nlm4_testres *arg, struct svc_req *rqstp)
115274462Salfred{
115374462Salfred	if (debug_level)
115474462Salfred		log_from_addr("nlm4_test_res", rqstp);
115575631Salfred
115675631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat,
115775631Salfred		(int *)&arg->stat.nlm4_testrply_u.holder.svid,
115875631Salfred		NLM_VERS4);
115974462Salfred	return (NULL);
116074462Salfred}
116174462Salfred
116274462Salfred/* nlm_lock_res ------------------------------------------------------------ */
116374462Salfred/*
116474462Salfred * Purpose:	Accept result from earlier nlm_lock_msg() call
116574462Salfred * Returns:	Nothing
116674462Salfred */
116774462Salfredvoid *
1168260250Sdelphijnlm4_lock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
116974462Salfred{
117074462Salfred	if (debug_level)
117174462Salfred		log_from_addr("nlm4_lock_res", rqstp);
117274462Salfred
117375631Salfred	(void)lock_answer(-1, &arg->cookie, arg->stat.stat, NULL, NLM_VERS4);
117475631Salfred
117574462Salfred	return (NULL);
117674462Salfred}
117774462Salfred
117874462Salfred/* nlm_cancel_res ---------------------------------------------------------- */
117974462Salfred/*
118074462Salfred * Purpose:	Accept result from earlier nlm_cancel_msg() call
118174462Salfred * Returns:	Nothing
118274462Salfred */
118374462Salfredvoid *
1184260250Sdelphijnlm4_cancel_res_4_svc(nlm4_res *arg __unused, struct svc_req *rqstp)
118574462Salfred{
118674462Salfred	if (debug_level)
118774462Salfred		log_from_addr("nlm4_cancel_res", rqstp);
118874462Salfred	return (NULL);
118974462Salfred}
119074462Salfred
119174462Salfred/* nlm_unlock_res ---------------------------------------------------------- */
119274462Salfred/*
119374462Salfred * Purpose:	Accept result from earlier nlm_unlock_msg() call
119474462Salfred * Returns:	Nothing
119574462Salfred */
119674462Salfredvoid *
1197260250Sdelphijnlm4_unlock_res_4_svc(nlm4_res *arg __unused, struct svc_req *rqstp)
119874462Salfred{
119974462Salfred	if (debug_level)
120074462Salfred		log_from_addr("nlm4_unlock_res", rqstp);
120174462Salfred	return (NULL);
120274462Salfred}
120374462Salfred
120474462Salfred/* nlm_granted_res --------------------------------------------------------- */
120574462Salfred/*
120674462Salfred * Purpose:	Accept result from earlier nlm_granted_msg() call
120774462Salfred * Returns:	Nothing
120874462Salfred */
120974462Salfredvoid *
1210260250Sdelphijnlm4_granted_res_4_svc(nlm4_res *arg __unused, struct svc_req *rqstp)
121174462Salfred{
121274462Salfred	if (debug_level)
121374462Salfred		log_from_addr("nlm4_granted_res", rqstp);
121474462Salfred	return (NULL);
121574462Salfred}
121674462Salfred
121774462Salfred/* ------------------------------------------------------------------------- */
121874462Salfred/*
121974462Salfred * Calls for PCNFS locking (aka non-monitored locking, no involvement
122074462Salfred * of rpc.statd).
122174462Salfred *
122274462Salfred * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
122374462Salfred */
122474462Salfred
122574462Salfred/* nlm_share --------------------------------------------------------------- */
122674462Salfred/*
122774462Salfred * Purpose:	Establish a DOS-style lock
122874462Salfred * Returns:	success or failure
122974462Salfred * Notes:	Blocking locks are not supported - client is expected
123074462Salfred *		to retry if required.
123174462Salfred */
123274462Salfrednlm4_shareres *
1233260250Sdelphijnlm4_share_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
123474462Salfred{
123574462Salfred	static nlm4_shareres res;
123674462Salfred
123774462Salfred	if (debug_level)
123874462Salfred		log_from_addr("nlm4_share", rqstp);
123974462Salfred
124074462Salfred	res.cookie = arg->cookie;
124174462Salfred	res.stat = nlm4_granted;
124274462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
124374462Salfred	return (&res);
124474462Salfred}
124574462Salfred
124674462Salfred/* nlm4_unshare ------------------------------------------------------------ */
124774462Salfred/*
124874462Salfred * Purpose:	Release a DOS-style lock
124974462Salfred * Returns:	nlm_granted, unless in grace period
125074462Salfred * Notes:
125174462Salfred */
125274462Salfrednlm4_shareres *
1253260250Sdelphijnlm4_unshare_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
125474462Salfred{
125574462Salfred	static nlm4_shareres res;
125674462Salfred
125774462Salfred	if (debug_level)
125874462Salfred		log_from_addr("nlm_unshare", rqstp);
125974462Salfred
126074462Salfred	res.cookie = arg->cookie;
126174462Salfred	res.stat = nlm4_granted;
126274462Salfred	res.sequence = 1234356;	/* X/Open says this field is ignored? */
126374462Salfred	return (&res);
126474462Salfred}
126574462Salfred
126674462Salfred/* nlm4_nm_lock ------------------------------------------------------------ */
126774462Salfred/*
126874462Salfred * Purpose:	non-monitored version of nlm4_lock()
126974462Salfred * Returns:	as for nlm4_lock()
127074462Salfred * Notes:	These locks are in the same style as the standard nlm4_lock,
127174462Salfred *		but the rpc.statd should not be called to establish a
127274462Salfred *		monitor for the client machine, since that machine is
127374462Salfred *		declared not to be running a rpc.statd, and so would not
127474462Salfred *		respond to the statd protocol.
127574462Salfred */
127674462Salfrednlm4_res *
1277260250Sdelphijnlm4_nm_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
127874462Salfred{
127974462Salfred	static nlm4_res res;
128074462Salfred
128174462Salfred	if (debug_level)
128274462Salfred		log_from_addr("nlm4_nm_lock", rqstp);
128374462Salfred
128474462Salfred	/* copy cookie from arg to result.  See comment in nlm4_test_1() */
128574462Salfred	res.cookie = arg->cookie;
128674462Salfred	res.stat.stat = nlm4_granted;
128774462Salfred	return (&res);
128874462Salfred}
128974462Salfred
129074462Salfred/* nlm4_free_all ------------------------------------------------------------ */
129174462Salfred/*
129274462Salfred * Purpose:	Release all locks held by a named client
129374462Salfred * Returns:	Nothing
129474462Salfred * Notes:	Potential denial of service security problem here - the
129574462Salfred *		locks to be released are specified by a host name, independent
129674462Salfred *		of the address from which the request has arrived.
129774462Salfred *		Should probably be rejected if the named host has been
129874462Salfred *		using monitored locks.
129974462Salfred */
130074462Salfredvoid *
1301260250Sdelphijnlm4_free_all_4_svc(struct nlm4_notify *arg __unused, struct svc_req *rqstp)
130274462Salfred{
130374462Salfred	static char dummy;
130474462Salfred
130574462Salfred	if (debug_level)
130674462Salfred		log_from_addr("nlm4_free_all", rqstp);
130774462Salfred	return (&dummy);
130874462Salfred}
130974462Salfred
131074462Salfred/* nlm_sm_notify --------------------------------------------------------- */
131174462Salfred/*
131274462Salfred * Purpose:	called by rpc.statd when a monitored host state changes.
131374462Salfred * Returns:	Nothing
131474462Salfred */
131574462Salfredvoid *
1316260250Sdelphijnlm_sm_notify_0_svc(struct nlm_sm_status *arg, struct svc_req *rqstp __unused)
131774462Salfred{
131874462Salfred	static char dummy;
131974462Salfred	notify(arg->mon_name, arg->state);
132074462Salfred	return (&dummy);
132174462Salfred}
1322