xref: /dflybsd-src/usr.sbin/rpc.lockd/lock_proc.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * Copyright (c) 1995
3*86d7f5d3SJohn Marino  *	A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
4*86d7f5d3SJohn Marino  *
5*86d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
6*86d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
7*86d7f5d3SJohn Marino  * are met:
8*86d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
9*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
10*86d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
11*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
12*86d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
13*86d7f5d3SJohn Marino  * 3. All advertising materials mentioning features or use of this software
14*86d7f5d3SJohn Marino  *    must display the following acknowledgement:
15*86d7f5d3SJohn Marino  *	This product includes software developed for the FreeBSD project
16*86d7f5d3SJohn Marino  * 4. Neither the name of the author nor the names of any co-contributors
17*86d7f5d3SJohn Marino  *    may be used to endorse or promote products derived from this software
18*86d7f5d3SJohn Marino  *    without specific prior written permission.
19*86d7f5d3SJohn Marino  *
20*86d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
21*86d7f5d3SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*86d7f5d3SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*86d7f5d3SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24*86d7f5d3SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*86d7f5d3SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*86d7f5d3SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*86d7f5d3SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*86d7f5d3SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*86d7f5d3SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*86d7f5d3SJohn Marino  * SUCH DAMAGE.
31*86d7f5d3SJohn Marino  *
32*86d7f5d3SJohn Marino  * $NetBSD: lock_proc.c,v 1.7 2000/10/11 20:23:56 is Exp $
33*86d7f5d3SJohn Marino  * $FreeBSD: src/usr.sbin/rpc.lockd/lock_proc.c,v 1.1 2001/03/19 12:50:09 alfred Exp $
34*86d7f5d3SJohn Marino  */
35*86d7f5d3SJohn Marino 
36*86d7f5d3SJohn Marino #include <sys/param.h>
37*86d7f5d3SJohn Marino #include <sys/socket.h>
38*86d7f5d3SJohn Marino 
39*86d7f5d3SJohn Marino #include <netinet/in.h>
40*86d7f5d3SJohn Marino #include <arpa/inet.h>
41*86d7f5d3SJohn Marino 
42*86d7f5d3SJohn Marino #include <netdb.h>
43*86d7f5d3SJohn Marino #include <stdio.h>
44*86d7f5d3SJohn Marino #include <string.h>
45*86d7f5d3SJohn Marino #include <syslog.h>
46*86d7f5d3SJohn Marino #include <unistd.h>
47*86d7f5d3SJohn Marino #include <netconfig.h>
48*86d7f5d3SJohn Marino 
49*86d7f5d3SJohn Marino #include <rpc/rpc.h>
50*86d7f5d3SJohn Marino #include <rpcsvc/sm_inter.h>
51*86d7f5d3SJohn Marino 
52*86d7f5d3SJohn Marino #include "lockd.h"
53*86d7f5d3SJohn Marino #include <rpcsvc/nlm_prot.h>
54*86d7f5d3SJohn Marino #include "lockd_lock.h"
55*86d7f5d3SJohn Marino 
56*86d7f5d3SJohn Marino 
57*86d7f5d3SJohn Marino #define	CLIENT_CACHE_SIZE	64	/* No. of client sockets cached */
58*86d7f5d3SJohn Marino #define	CLIENT_CACHE_LIFETIME	120	/* In seconds */
59*86d7f5d3SJohn Marino 
60*86d7f5d3SJohn Marino #define	getrpcaddr(rqstp)	(struct sockaddr *)(svc_getrpccaller((rqstp)->rq_xprt)->buf)
61*86d7f5d3SJohn Marino 
62*86d7f5d3SJohn Marino static void	log_from_addr(const char *, struct svc_req *);
63*86d7f5d3SJohn Marino static int	addrcmp(struct sockaddr *, struct sockaddr *);
64*86d7f5d3SJohn Marino 
65*86d7f5d3SJohn Marino /* log_from_addr ----------------------------------------------------------- */
66*86d7f5d3SJohn Marino /*
67*86d7f5d3SJohn Marino  * Purpose:	Log name of function called and source address
68*86d7f5d3SJohn Marino  * Returns:	Nothing
69*86d7f5d3SJohn Marino  * Notes:	Extracts the source address from the transport handle
70*86d7f5d3SJohn Marino  *		passed in as part of the called procedure specification
71*86d7f5d3SJohn Marino  */
72*86d7f5d3SJohn Marino static void
log_from_addr(const char * fun_name,struct svc_req * req)73*86d7f5d3SJohn Marino log_from_addr(const char *fun_name, struct svc_req *req)
74*86d7f5d3SJohn Marino {
75*86d7f5d3SJohn Marino 	struct sockaddr *addr;
76*86d7f5d3SJohn Marino 	char hostname_buf[NI_MAXHOST];
77*86d7f5d3SJohn Marino 
78*86d7f5d3SJohn Marino 	addr = svc_getrpccaller(req->rq_xprt)->buf;
79*86d7f5d3SJohn Marino 	if (getnameinfo(addr , addr->sa_len, hostname_buf, sizeof hostname_buf,
80*86d7f5d3SJohn Marino 	    NULL, 0, 0) != 0)
81*86d7f5d3SJohn Marino 		return;
82*86d7f5d3SJohn Marino 
83*86d7f5d3SJohn Marino 	syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
84*86d7f5d3SJohn Marino }
85*86d7f5d3SJohn Marino 
86*86d7f5d3SJohn Marino /* get_client -------------------------------------------------------------- */
87*86d7f5d3SJohn Marino /*
88*86d7f5d3SJohn Marino  * Purpose:	Get a CLIENT* for making RPC calls to lockd on given host
89*86d7f5d3SJohn Marino  * Returns:	CLIENT* pointer, from clnt_udp_create, or NULL if error
90*86d7f5d3SJohn Marino  * Notes:	Creating a CLIENT* is quite expensive, involving a
91*86d7f5d3SJohn Marino  *		conversation with the remote portmapper to get the
92*86d7f5d3SJohn Marino  *		port number.  Since a given client is quite likely
93*86d7f5d3SJohn Marino  *		to make several locking requests in succession, it is
94*86d7f5d3SJohn Marino  *		desirable to cache the created CLIENT*.
95*86d7f5d3SJohn Marino  *
96*86d7f5d3SJohn Marino  *		Since we are using UDP rather than TCP, there is no cost
97*86d7f5d3SJohn Marino  *		to the remote system in keeping these cached indefinitely.
98*86d7f5d3SJohn Marino  *		Unfortunately there is a snag: if the remote system
99*86d7f5d3SJohn Marino  *		reboots, the cached portmapper results will be invalid,
100*86d7f5d3SJohn Marino  *		and we will never detect this since all of the xxx_msg()
101*86d7f5d3SJohn Marino  *		calls return no result - we just fire off a udp packet
102*86d7f5d3SJohn Marino  *		and hope for the best.
103*86d7f5d3SJohn Marino  *
104*86d7f5d3SJohn Marino  *		We solve this by discarding cached values after two
105*86d7f5d3SJohn Marino  *		minutes, regardless of whether they have been used
106*86d7f5d3SJohn Marino  *		in the meanwhile (since a bad one might have been used
107*86d7f5d3SJohn Marino  *		plenty of times, as the host keeps retrying the request
108*86d7f5d3SJohn Marino  *		and we keep sending the reply back to the wrong port).
109*86d7f5d3SJohn Marino  *
110*86d7f5d3SJohn Marino  *		Given that the entries will always expire in the order
111*86d7f5d3SJohn Marino  *		that they were created, there is no point in a LRU
112*86d7f5d3SJohn Marino  *		algorithm for when the cache gets full - entries are
113*86d7f5d3SJohn Marino  *		always re-used in sequence.
114*86d7f5d3SJohn Marino  */
115*86d7f5d3SJohn Marino static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
116*86d7f5d3SJohn Marino static long clnt_cache_time[CLIENT_CACHE_SIZE];	/* time entry created */
117*86d7f5d3SJohn Marino static struct sockaddr_storage clnt_cache_addr[CLIENT_CACHE_SIZE];
118*86d7f5d3SJohn Marino static rpcvers_t clnt_cache_vers[CLIENT_CACHE_SIZE];
119*86d7f5d3SJohn Marino static int clnt_cache_next_to_use = 0;
120*86d7f5d3SJohn Marino 
121*86d7f5d3SJohn Marino static int
addrcmp(struct sockaddr * sa1,struct sockaddr * sa2)122*86d7f5d3SJohn Marino addrcmp(struct sockaddr *sa1, struct sockaddr *sa2)
123*86d7f5d3SJohn Marino {
124*86d7f5d3SJohn Marino 	int len;
125*86d7f5d3SJohn Marino 	void *p1, *p2;
126*86d7f5d3SJohn Marino 
127*86d7f5d3SJohn Marino 	if (sa1->sa_family != sa2->sa_family)
128*86d7f5d3SJohn Marino 		return -1;
129*86d7f5d3SJohn Marino 
130*86d7f5d3SJohn Marino 	switch (sa1->sa_family) {
131*86d7f5d3SJohn Marino 	case AF_INET:
132*86d7f5d3SJohn Marino 		p1 = &((struct sockaddr_in *)sa1)->sin_addr;
133*86d7f5d3SJohn Marino 		p2 = &((struct sockaddr_in *)sa2)->sin_addr;
134*86d7f5d3SJohn Marino 		len = 4;
135*86d7f5d3SJohn Marino 		break;
136*86d7f5d3SJohn Marino 	case AF_INET6:
137*86d7f5d3SJohn Marino 		p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
138*86d7f5d3SJohn Marino 		p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
139*86d7f5d3SJohn Marino 		len = 16;
140*86d7f5d3SJohn Marino 		break;
141*86d7f5d3SJohn Marino 	default:
142*86d7f5d3SJohn Marino 		return -1;
143*86d7f5d3SJohn Marino 	}
144*86d7f5d3SJohn Marino 
145*86d7f5d3SJohn Marino 	return memcmp(p1, p2, len);
146*86d7f5d3SJohn Marino }
147*86d7f5d3SJohn Marino 
148*86d7f5d3SJohn Marino CLIENT *
get_client(struct sockaddr * host_addr,rpcvers_t vers)149*86d7f5d3SJohn Marino get_client(struct sockaddr *host_addr, rpcvers_t vers)
150*86d7f5d3SJohn Marino {
151*86d7f5d3SJohn Marino 	CLIENT *client;
152*86d7f5d3SJohn Marino 	struct timeval retry_time, time_now;
153*86d7f5d3SJohn Marino 	int error, i;
154*86d7f5d3SJohn Marino 	const char *netid;
155*86d7f5d3SJohn Marino 	struct netconfig *nconf;
156*86d7f5d3SJohn Marino 	char host[NI_MAXHOST];
157*86d7f5d3SJohn Marino 	uid_t old_euid;
158*86d7f5d3SJohn Marino 	int clnt_fd;
159*86d7f5d3SJohn Marino 
160*86d7f5d3SJohn Marino 	gettimeofday(&time_now, NULL);
161*86d7f5d3SJohn Marino 
162*86d7f5d3SJohn Marino 	/*
163*86d7f5d3SJohn Marino 	 * Search for the given client in the cache, zapping any expired
164*86d7f5d3SJohn Marino 	 * entries that we happen to notice in passing.
165*86d7f5d3SJohn Marino 	 */
166*86d7f5d3SJohn Marino 	for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
167*86d7f5d3SJohn Marino 		client = clnt_cache_ptr[i];
168*86d7f5d3SJohn Marino 		if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
169*86d7f5d3SJohn Marino 		    < time_now.tv_sec)) {
170*86d7f5d3SJohn Marino 			/* Cache entry has expired. */
171*86d7f5d3SJohn Marino 			if (debug_level > 3)
172*86d7f5d3SJohn Marino 				syslog(LOG_DEBUG, "Expired CLIENT* in cache");
173*86d7f5d3SJohn Marino 			clnt_cache_time[i] = 0L;
174*86d7f5d3SJohn Marino 			clnt_destroy(client);
175*86d7f5d3SJohn Marino 			clnt_cache_ptr[i] = NULL;
176*86d7f5d3SJohn Marino 			client = NULL;
177*86d7f5d3SJohn Marino 		}
178*86d7f5d3SJohn Marino 		if (client && !addrcmp((struct sockaddr *)&clnt_cache_addr[i],
179*86d7f5d3SJohn Marino 		    host_addr) && clnt_cache_vers[i] == vers) {
180*86d7f5d3SJohn Marino 			/* Found it! */
181*86d7f5d3SJohn Marino 			if (debug_level > 3)
182*86d7f5d3SJohn Marino 				syslog(LOG_DEBUG, "Found CLIENT* in cache");
183*86d7f5d3SJohn Marino 			return (client);
184*86d7f5d3SJohn Marino 		}
185*86d7f5d3SJohn Marino 	}
186*86d7f5d3SJohn Marino 
187*86d7f5d3SJohn Marino 	if (debug_level > 3)
188*86d7f5d3SJohn Marino 		syslog(LOG_DEBUG, "CLIENT* not found in cache, creating");
189*86d7f5d3SJohn Marino 
190*86d7f5d3SJohn Marino 	/* Not found in cache.  Free the next entry if it is in use. */
191*86d7f5d3SJohn Marino 	if (clnt_cache_ptr[clnt_cache_next_to_use]) {
192*86d7f5d3SJohn Marino 		clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
193*86d7f5d3SJohn Marino 		clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
194*86d7f5d3SJohn Marino 	}
195*86d7f5d3SJohn Marino 
196*86d7f5d3SJohn Marino 	/*
197*86d7f5d3SJohn Marino 	 * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
198*86d7f5d3SJohn Marino 	 * to avoid DNS lookups.
199*86d7f5d3SJohn Marino 	 */
200*86d7f5d3SJohn Marino 	error = getnameinfo(host_addr, host_addr->sa_len, host, sizeof host,
201*86d7f5d3SJohn Marino 			    NULL, 0, NI_NUMERICHOST);
202*86d7f5d3SJohn Marino 	if (error != 0) {
203*86d7f5d3SJohn Marino 		syslog(LOG_ERR, "unable to get name string for caller: %s",
204*86d7f5d3SJohn Marino 		       gai_strerror(error));
205*86d7f5d3SJohn Marino 		return NULL;
206*86d7f5d3SJohn Marino 	}
207*86d7f5d3SJohn Marino 
208*86d7f5d3SJohn Marino #if 1
209*86d7f5d3SJohn Marino 	if (host_addr->sa_family == AF_INET6)
210*86d7f5d3SJohn Marino 		netid = "udp6";
211*86d7f5d3SJohn Marino 	else
212*86d7f5d3SJohn Marino 		netid = "udp";
213*86d7f5d3SJohn Marino #else
214*86d7f5d3SJohn Marino 	if (host_addr->sa_family == AF_INET6)
215*86d7f5d3SJohn Marino 		netid = "tcp6";
216*86d7f5d3SJohn Marino 	else
217*86d7f5d3SJohn Marino 		netid = "tcp";
218*86d7f5d3SJohn Marino #endif
219*86d7f5d3SJohn Marino 	nconf = getnetconfigent(netid);
220*86d7f5d3SJohn Marino 	if (nconf == NULL) {
221*86d7f5d3SJohn Marino 		syslog(LOG_ERR, "could not get netconfig info for '%s': "
222*86d7f5d3SJohn Marino 				"no /etc/netconfig file?", netid);
223*86d7f5d3SJohn Marino 		return NULL;
224*86d7f5d3SJohn Marino 	}
225*86d7f5d3SJohn Marino 
226*86d7f5d3SJohn Marino 	client = clnt_tp_create(host, NLM_PROG, vers, nconf);
227*86d7f5d3SJohn Marino 	freenetconfigent(nconf);
228*86d7f5d3SJohn Marino 
229*86d7f5d3SJohn Marino 	if (!client) {
230*86d7f5d3SJohn Marino 		syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create"));
231*86d7f5d3SJohn Marino 		syslog(LOG_ERR, "Unable to return result to %s", host);
232*86d7f5d3SJohn Marino 		return NULL;
233*86d7f5d3SJohn Marino 	}
234*86d7f5d3SJohn Marino 
235*86d7f5d3SJohn Marino 	/* Get the FD of the client, for bindresvport. */
236*86d7f5d3SJohn Marino 	clnt_control(client, CLGET_FD, &clnt_fd);
237*86d7f5d3SJohn Marino 
238*86d7f5d3SJohn Marino 	/* Regain root privileges, for bindresvport. */
239*86d7f5d3SJohn Marino 	old_euid = geteuid();
240*86d7f5d3SJohn Marino 	seteuid(0);
241*86d7f5d3SJohn Marino 
242*86d7f5d3SJohn Marino 	/*
243*86d7f5d3SJohn Marino 	 * Bind the client FD to a reserved port.
244*86d7f5d3SJohn Marino 	 * Some NFS servers reject any NLM request from a non-reserved port.
245*86d7f5d3SJohn Marino 	 */
246*86d7f5d3SJohn Marino 	bindresvport(clnt_fd, NULL);
247*86d7f5d3SJohn Marino 
248*86d7f5d3SJohn Marino 	/* Drop root privileges again. */
249*86d7f5d3SJohn Marino 	seteuid(old_euid);
250*86d7f5d3SJohn Marino 
251*86d7f5d3SJohn Marino 	/* Success - update the cache entry */
252*86d7f5d3SJohn Marino 	clnt_cache_ptr[clnt_cache_next_to_use] = client;
253*86d7f5d3SJohn Marino 	memcpy(&clnt_cache_addr[clnt_cache_next_to_use], host_addr,
254*86d7f5d3SJohn Marino 	    host_addr->sa_len);
255*86d7f5d3SJohn Marino 	clnt_cache_vers[clnt_cache_next_to_use] = vers;
256*86d7f5d3SJohn Marino 	clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
257*86d7f5d3SJohn Marino 	if (++clnt_cache_next_to_use >= CLIENT_CACHE_SIZE)
258*86d7f5d3SJohn Marino 		clnt_cache_next_to_use = 0;
259*86d7f5d3SJohn Marino 
260*86d7f5d3SJohn Marino 	/*
261*86d7f5d3SJohn Marino 	 * Disable the default timeout, so we can specify our own in calls
262*86d7f5d3SJohn Marino 	 * to clnt_call().  (Note that the timeout is a different concept
263*86d7f5d3SJohn Marino 	 * from the retry period set in clnt_udp_create() above.)
264*86d7f5d3SJohn Marino 	 */
265*86d7f5d3SJohn Marino 	retry_time.tv_sec = -1;
266*86d7f5d3SJohn Marino 	retry_time.tv_usec = -1;
267*86d7f5d3SJohn Marino 	clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
268*86d7f5d3SJohn Marino 
269*86d7f5d3SJohn Marino 	if (debug_level > 3)
270*86d7f5d3SJohn Marino 		syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
271*86d7f5d3SJohn Marino 	return client;
272*86d7f5d3SJohn Marino }
273*86d7f5d3SJohn Marino 
274*86d7f5d3SJohn Marino 
275*86d7f5d3SJohn Marino /* transmit_result --------------------------------------------------------- */
276*86d7f5d3SJohn Marino /*
277*86d7f5d3SJohn Marino  * Purpose:	Transmit result for nlm_xxx_msg pseudo-RPCs
278*86d7f5d3SJohn Marino  * Returns:	Nothing - we have no idea if the datagram got there
279*86d7f5d3SJohn Marino  * Notes:	clnt_call() will always fail (with timeout) as we are
280*86d7f5d3SJohn Marino  *		calling it with timeout 0 as a hack to just issue a datagram
281*86d7f5d3SJohn Marino  *		without expecting a result
282*86d7f5d3SJohn Marino  */
283*86d7f5d3SJohn Marino void
transmit_result(int opcode,nlm_res * result,struct sockaddr * addr)284*86d7f5d3SJohn Marino transmit_result(int opcode, nlm_res *result, struct sockaddr *addr)
285*86d7f5d3SJohn Marino {
286*86d7f5d3SJohn Marino 	static char dummy;
287*86d7f5d3SJohn Marino 	CLIENT *cli;
288*86d7f5d3SJohn Marino 	struct timeval timeo;
289*86d7f5d3SJohn Marino 	int success;
290*86d7f5d3SJohn Marino 
291*86d7f5d3SJohn Marino 	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
292*86d7f5d3SJohn Marino 		timeo.tv_sec = 0; /* No timeout - not expecting response */
293*86d7f5d3SJohn Marino 		timeo.tv_usec = 0;
294*86d7f5d3SJohn Marino 
295*86d7f5d3SJohn Marino 		success = clnt_call(cli, opcode, (xdrproc_t)xdr_nlm_res, result,
296*86d7f5d3SJohn Marino 		    (xdrproc_t)xdr_void, &dummy, timeo);
297*86d7f5d3SJohn Marino 
298*86d7f5d3SJohn Marino 		if (debug_level > 2)
299*86d7f5d3SJohn Marino 			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
300*86d7f5d3SJohn Marino 			    success, clnt_sperrno(success));
301*86d7f5d3SJohn Marino 	}
302*86d7f5d3SJohn Marino }
303*86d7f5d3SJohn Marino /* transmit4_result --------------------------------------------------------- */
304*86d7f5d3SJohn Marino /*
305*86d7f5d3SJohn Marino  * Purpose:	Transmit result for nlm4_xxx_msg pseudo-RPCs
306*86d7f5d3SJohn Marino  * Returns:	Nothing - we have no idea if the datagram got there
307*86d7f5d3SJohn Marino  * Notes:	clnt_call() will always fail (with timeout) as we are
308*86d7f5d3SJohn Marino  *		calling it with timeout 0 as a hack to just issue a datagram
309*86d7f5d3SJohn Marino  *		without expecting a result
310*86d7f5d3SJohn Marino  */
311*86d7f5d3SJohn Marino void
transmit4_result(int opcode,nlm4_res * result,struct sockaddr * addr)312*86d7f5d3SJohn Marino transmit4_result(int opcode, nlm4_res *result, struct sockaddr *addr)
313*86d7f5d3SJohn Marino {
314*86d7f5d3SJohn Marino 	static char dummy;
315*86d7f5d3SJohn Marino 	CLIENT *cli;
316*86d7f5d3SJohn Marino 	struct timeval timeo;
317*86d7f5d3SJohn Marino 	int success;
318*86d7f5d3SJohn Marino 
319*86d7f5d3SJohn Marino 	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
320*86d7f5d3SJohn Marino 		timeo.tv_sec = 0; /* No timeout - not expecting response */
321*86d7f5d3SJohn Marino 		timeo.tv_usec = 0;
322*86d7f5d3SJohn Marino 
323*86d7f5d3SJohn Marino 		success = clnt_call(cli, opcode,
324*86d7f5d3SJohn Marino 		    (xdrproc_t)xdr_nlm4_res, result,
325*86d7f5d3SJohn Marino 		    (xdrproc_t)xdr_void, &dummy, timeo);
326*86d7f5d3SJohn Marino 
327*86d7f5d3SJohn Marino 		if (debug_level > 2)
328*86d7f5d3SJohn Marino 			syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
329*86d7f5d3SJohn Marino 			    success, clnt_sperrno(success));
330*86d7f5d3SJohn Marino 	}
331*86d7f5d3SJohn Marino }
332*86d7f5d3SJohn Marino 
333*86d7f5d3SJohn Marino /*
334*86d7f5d3SJohn Marino  * converts a struct nlm_lock to struct nlm4_lock
335*86d7f5d3SJohn Marino  */
336*86d7f5d3SJohn Marino static void nlmtonlm4(struct nlm_lock *, struct nlm4_lock *);
337*86d7f5d3SJohn Marino static void
nlmtonlm4(struct nlm_lock * arg,struct nlm4_lock * arg4)338*86d7f5d3SJohn Marino nlmtonlm4(struct nlm_lock *arg, struct nlm4_lock *arg4)
339*86d7f5d3SJohn Marino {
340*86d7f5d3SJohn Marino 	arg4->caller_name = arg->caller_name;
341*86d7f5d3SJohn Marino 	arg4->fh = arg->fh;
342*86d7f5d3SJohn Marino 	arg4->oh = arg->oh;
343*86d7f5d3SJohn Marino 	arg4->svid = arg->svid;
344*86d7f5d3SJohn Marino 	arg4->l_offset = arg->l_offset;
345*86d7f5d3SJohn Marino 	arg4->l_len = arg->l_len;
346*86d7f5d3SJohn Marino }
347*86d7f5d3SJohn Marino /* ------------------------------------------------------------------------- */
348*86d7f5d3SJohn Marino /*
349*86d7f5d3SJohn Marino  * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
350*86d7f5d3SJohn Marino  * involved to ensure reclaim of locks after a crash of the "stateless"
351*86d7f5d3SJohn Marino  * server.
352*86d7f5d3SJohn Marino  *
353*86d7f5d3SJohn Marino  * These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
354*86d7f5d3SJohn Marino  * The first are standard RPCs with argument and result.
355*86d7f5d3SJohn Marino  * The nlm_xxx_msg() calls implement exactly the same functions, but
356*86d7f5d3SJohn Marino  * use two pseudo-RPCs (one in each direction).  These calls are NOT
357*86d7f5d3SJohn Marino  * standard use of the RPC protocol in that they do not return a result
358*86d7f5d3SJohn Marino  * at all (NB. this is quite different from returning a void result).
359*86d7f5d3SJohn Marino  * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
360*86d7f5d3SJohn Marino  * datagrams, requiring higher-level code to perform retries.
361*86d7f5d3SJohn Marino  *
362*86d7f5d3SJohn Marino  * Despite the disadvantages of the nlm_xxx_msg() approach (some of which
363*86d7f5d3SJohn Marino  * are documented in the comments to get_client() above), this is the
364*86d7f5d3SJohn Marino  * interface used by all current commercial NFS implementations
365*86d7f5d3SJohn Marino  * [Solaris, SCO, AIX etc.].  This is presumed to be because these allow
366*86d7f5d3SJohn Marino  * implementations to continue using the standard RPC libraries, while
367*86d7f5d3SJohn Marino  * avoiding the block-until-result nature of the library interface.
368*86d7f5d3SJohn Marino  *
369*86d7f5d3SJohn Marino  * No client implementations have been identified so far that make use
370*86d7f5d3SJohn Marino  * of the true RPC version (early SunOS releases would be a likely candidate
371*86d7f5d3SJohn Marino  * for testing).
372*86d7f5d3SJohn Marino  */
373*86d7f5d3SJohn Marino 
374*86d7f5d3SJohn Marino /* nlm_test ---------------------------------------------------------------- */
375*86d7f5d3SJohn Marino /*
376*86d7f5d3SJohn Marino  * Purpose:	Test whether a specified lock would be granted if requested
377*86d7f5d3SJohn Marino  * Returns:	nlm_granted (or error code)
378*86d7f5d3SJohn Marino  * Notes:
379*86d7f5d3SJohn Marino  */
380*86d7f5d3SJohn Marino nlm_testres *
nlm_test_1_svc(nlm_testargs * arg,struct svc_req * rqstp)381*86d7f5d3SJohn Marino nlm_test_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
382*86d7f5d3SJohn Marino {
383*86d7f5d3SJohn Marino 	static nlm_testres res;
384*86d7f5d3SJohn Marino 	struct nlm4_lock arg4;
385*86d7f5d3SJohn Marino 	struct nlm4_holder *holder;
386*86d7f5d3SJohn Marino 	nlmtonlm4(&arg->alock, &arg4);
387*86d7f5d3SJohn Marino 
388*86d7f5d3SJohn Marino 	if (debug_level)
389*86d7f5d3SJohn Marino 		log_from_addr("nlm_test", rqstp);
390*86d7f5d3SJohn Marino 
391*86d7f5d3SJohn Marino 	holder = testlock(&arg4, 0);
392*86d7f5d3SJohn Marino 	/*
393*86d7f5d3SJohn Marino 	 * Copy the cookie from the argument into the result.  Note that this
394*86d7f5d3SJohn Marino 	 * is slightly hazardous, as the structure contains a pointer to a
395*86d7f5d3SJohn Marino 	 * malloc()ed buffer that will get freed by the caller.  However, the
396*86d7f5d3SJohn Marino 	 * main function transmits the result before freeing the argument
397*86d7f5d3SJohn Marino 	 * so it is in fact safe.
398*86d7f5d3SJohn Marino 	 */
399*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
400*86d7f5d3SJohn Marino 	if (holder == NULL) {
401*86d7f5d3SJohn Marino 		res.stat.stat = nlm_granted;
402*86d7f5d3SJohn Marino 	} else {
403*86d7f5d3SJohn Marino 		res.stat.stat = nlm_denied;
404*86d7f5d3SJohn Marino 		memcpy(&res.stat.nlm_testrply_u.holder, holder,
405*86d7f5d3SJohn Marino 		    sizeof(struct nlm_holder));
406*86d7f5d3SJohn Marino 		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
407*86d7f5d3SJohn Marino 		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
408*86d7f5d3SJohn Marino 	}
409*86d7f5d3SJohn Marino 	return (&res);
410*86d7f5d3SJohn Marino }
411*86d7f5d3SJohn Marino 
412*86d7f5d3SJohn Marino void *
nlm_test_msg_1_svc(nlm_testargs * arg,struct svc_req * rqstp)413*86d7f5d3SJohn Marino nlm_test_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
414*86d7f5d3SJohn Marino {
415*86d7f5d3SJohn Marino 	nlm_testres res;
416*86d7f5d3SJohn Marino 	static char dummy;
417*86d7f5d3SJohn Marino 	struct sockaddr *addr;
418*86d7f5d3SJohn Marino 	CLIENT *cli;
419*86d7f5d3SJohn Marino 	int success;
420*86d7f5d3SJohn Marino 	struct timeval timeo;
421*86d7f5d3SJohn Marino 	struct nlm4_lock arg4;
422*86d7f5d3SJohn Marino 	struct nlm4_holder *holder;
423*86d7f5d3SJohn Marino 
424*86d7f5d3SJohn Marino 	nlmtonlm4(&arg->alock, &arg4);
425*86d7f5d3SJohn Marino 
426*86d7f5d3SJohn Marino 	if (debug_level)
427*86d7f5d3SJohn Marino 		log_from_addr("nlm_test_msg", rqstp);
428*86d7f5d3SJohn Marino 
429*86d7f5d3SJohn Marino 	holder = testlock(&arg4, 0);
430*86d7f5d3SJohn Marino 
431*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
432*86d7f5d3SJohn Marino 	if (holder == NULL) {
433*86d7f5d3SJohn Marino 		res.stat.stat = nlm_granted;
434*86d7f5d3SJohn Marino 	} else {
435*86d7f5d3SJohn Marino 		res.stat.stat = nlm_denied;
436*86d7f5d3SJohn Marino 		memcpy(&res.stat.nlm_testrply_u.holder, holder,
437*86d7f5d3SJohn Marino 		    sizeof(struct nlm_holder));
438*86d7f5d3SJohn Marino 		res.stat.nlm_testrply_u.holder.l_offset = holder->l_offset;
439*86d7f5d3SJohn Marino 		res.stat.nlm_testrply_u.holder.l_len = holder->l_len;
440*86d7f5d3SJohn Marino 	}
441*86d7f5d3SJohn Marino 
442*86d7f5d3SJohn Marino 	/*
443*86d7f5d3SJohn Marino 	 * nlm_test has different result type to the other operations, so
444*86d7f5d3SJohn Marino 	 * can't use transmit_result() in this case
445*86d7f5d3SJohn Marino 	 */
446*86d7f5d3SJohn Marino 	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
447*86d7f5d3SJohn Marino 	if ((cli = get_client(addr, NLM_VERS)) != NULL) {
448*86d7f5d3SJohn Marino 		timeo.tv_sec = 0; /* No timeout - not expecting response */
449*86d7f5d3SJohn Marino 		timeo.tv_usec = 0;
450*86d7f5d3SJohn Marino 
451*86d7f5d3SJohn Marino 		success = clnt_call(cli, NLM_TEST_RES,
452*86d7f5d3SJohn Marino 		    (xdrproc_t)xdr_nlm_testres, &res,
453*86d7f5d3SJohn Marino 		    (xdrproc_t)xdr_void, &dummy, timeo);
454*86d7f5d3SJohn Marino 
455*86d7f5d3SJohn Marino 		if (debug_level > 2)
456*86d7f5d3SJohn Marino 			syslog(LOG_DEBUG, "clnt_call returns %d", success);
457*86d7f5d3SJohn Marino 	}
458*86d7f5d3SJohn Marino 	return (NULL);
459*86d7f5d3SJohn Marino }
460*86d7f5d3SJohn Marino 
461*86d7f5d3SJohn Marino /* nlm_lock ---------------------------------------------------------------- */
462*86d7f5d3SJohn Marino /*
463*86d7f5d3SJohn Marino  * Purposes:	Establish a lock
464*86d7f5d3SJohn Marino  * Returns:	granted, denied or blocked
465*86d7f5d3SJohn Marino  * Notes:	*** grace period support missing
466*86d7f5d3SJohn Marino  */
467*86d7f5d3SJohn Marino nlm_res *
nlm_lock_1_svc(nlm_lockargs * arg,struct svc_req * rqstp)468*86d7f5d3SJohn Marino nlm_lock_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
469*86d7f5d3SJohn Marino {
470*86d7f5d3SJohn Marino 	static nlm_res res;
471*86d7f5d3SJohn Marino 	struct nlm4_lockargs arg4;
472*86d7f5d3SJohn Marino 	nlmtonlm4(&arg->alock, &arg4.alock);
473*86d7f5d3SJohn Marino 	arg4.cookie = arg->cookie;
474*86d7f5d3SJohn Marino 	arg4.block = arg->block;
475*86d7f5d3SJohn Marino 	arg4.exclusive = arg->exclusive;
476*86d7f5d3SJohn Marino 	arg4.reclaim = arg->reclaim;
477*86d7f5d3SJohn Marino 	arg4.state = arg->state;
478*86d7f5d3SJohn Marino 
479*86d7f5d3SJohn Marino 	if (debug_level)
480*86d7f5d3SJohn Marino 		log_from_addr("nlm_lock", rqstp);
481*86d7f5d3SJohn Marino 
482*86d7f5d3SJohn Marino 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
483*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
484*86d7f5d3SJohn Marino 
485*86d7f5d3SJohn Marino 	res.stat.stat = getlock(&arg4, rqstp, LOCK_MON);
486*86d7f5d3SJohn Marino 	return (&res);
487*86d7f5d3SJohn Marino }
488*86d7f5d3SJohn Marino 
489*86d7f5d3SJohn Marino void *
nlm_lock_msg_1_svc(nlm_lockargs * arg,struct svc_req * rqstp)490*86d7f5d3SJohn Marino nlm_lock_msg_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
491*86d7f5d3SJohn Marino {
492*86d7f5d3SJohn Marino 	static nlm_res res;
493*86d7f5d3SJohn Marino 	struct nlm4_lockargs arg4;
494*86d7f5d3SJohn Marino 
495*86d7f5d3SJohn Marino 	nlmtonlm4(&arg->alock, &arg4.alock);
496*86d7f5d3SJohn Marino 	arg4.cookie = arg->cookie;
497*86d7f5d3SJohn Marino 	arg4.block = arg->block;
498*86d7f5d3SJohn Marino 	arg4.exclusive = arg->exclusive;
499*86d7f5d3SJohn Marino 	arg4.reclaim = arg->reclaim;
500*86d7f5d3SJohn Marino 	arg4.state = arg->state;
501*86d7f5d3SJohn Marino 
502*86d7f5d3SJohn Marino 	if (debug_level)
503*86d7f5d3SJohn Marino 		log_from_addr("nlm_lock_msg", rqstp);
504*86d7f5d3SJohn Marino 
505*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
506*86d7f5d3SJohn Marino 	res.stat.stat = getlock(&arg4, rqstp, LOCK_ASYNC | LOCK_MON);
507*86d7f5d3SJohn Marino 	transmit_result(NLM_LOCK_RES, &res, getrpcaddr(rqstp));
508*86d7f5d3SJohn Marino 
509*86d7f5d3SJohn Marino 	return (NULL);
510*86d7f5d3SJohn Marino }
511*86d7f5d3SJohn Marino 
512*86d7f5d3SJohn Marino /* nlm_cancel -------------------------------------------------------------- */
513*86d7f5d3SJohn Marino /*
514*86d7f5d3SJohn Marino  * Purpose:	Cancel a blocked lock request
515*86d7f5d3SJohn Marino  * Returns:	granted or denied
516*86d7f5d3SJohn Marino  * Notes:
517*86d7f5d3SJohn Marino  */
518*86d7f5d3SJohn Marino nlm_res *
nlm_cancel_1_svc(nlm_cancargs * arg,struct svc_req * rqstp)519*86d7f5d3SJohn Marino nlm_cancel_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
520*86d7f5d3SJohn Marino {
521*86d7f5d3SJohn Marino 	static nlm_res res;
522*86d7f5d3SJohn Marino 	struct nlm4_lock arg4;
523*86d7f5d3SJohn Marino 
524*86d7f5d3SJohn Marino 	nlmtonlm4(&arg->alock, &arg4);
525*86d7f5d3SJohn Marino 
526*86d7f5d3SJohn Marino 	if (debug_level)
527*86d7f5d3SJohn Marino 		log_from_addr("nlm_cancel", rqstp);
528*86d7f5d3SJohn Marino 
529*86d7f5d3SJohn Marino 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
530*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
531*86d7f5d3SJohn Marino 
532*86d7f5d3SJohn Marino 	/*
533*86d7f5d3SJohn Marino 	 * Since at present we never return 'nlm_blocked', there can never be
534*86d7f5d3SJohn Marino 	 * a lock to cancel, so this call always fails.
535*86d7f5d3SJohn Marino 	 */
536*86d7f5d3SJohn Marino 	res.stat.stat = unlock(&arg4, LOCK_CANCEL);
537*86d7f5d3SJohn Marino 	return (&res);
538*86d7f5d3SJohn Marino }
539*86d7f5d3SJohn Marino 
540*86d7f5d3SJohn Marino void *
nlm_cancel_msg_1_svc(nlm_cancargs * arg,struct svc_req * rqstp)541*86d7f5d3SJohn Marino nlm_cancel_msg_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
542*86d7f5d3SJohn Marino {
543*86d7f5d3SJohn Marino 	static nlm_res res;
544*86d7f5d3SJohn Marino 	struct nlm4_lock arg4;
545*86d7f5d3SJohn Marino 
546*86d7f5d3SJohn Marino 	nlmtonlm4(&arg->alock, &arg4);
547*86d7f5d3SJohn Marino 
548*86d7f5d3SJohn Marino 	if (debug_level)
549*86d7f5d3SJohn Marino 		log_from_addr("nlm_cancel_msg", rqstp);
550*86d7f5d3SJohn Marino 
551*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
552*86d7f5d3SJohn Marino 	/*
553*86d7f5d3SJohn Marino 	 * Since at present we never return 'nlm_blocked', there can never be
554*86d7f5d3SJohn Marino 	 * a lock to cancel, so this call always fails.
555*86d7f5d3SJohn Marino 	 */
556*86d7f5d3SJohn Marino 	res.stat.stat = unlock(&arg4, LOCK_CANCEL);
557*86d7f5d3SJohn Marino 	transmit_result(NLM_CANCEL_RES, &res, getrpcaddr(rqstp));
558*86d7f5d3SJohn Marino 	return (NULL);
559*86d7f5d3SJohn Marino }
560*86d7f5d3SJohn Marino 
561*86d7f5d3SJohn Marino /* nlm_unlock -------------------------------------------------------------- */
562*86d7f5d3SJohn Marino /*
563*86d7f5d3SJohn Marino  * Purpose:	Release an existing lock
564*86d7f5d3SJohn Marino  * Returns:	Always granted, unless during grace period
565*86d7f5d3SJohn Marino  * Notes:	"no such lock" error condition is ignored, as the
566*86d7f5d3SJohn Marino  *		protocol uses unreliable UDP datagrams, and may well
567*86d7f5d3SJohn Marino  *		re-try an unlock that has already succeeded.
568*86d7f5d3SJohn Marino  */
569*86d7f5d3SJohn Marino nlm_res *
nlm_unlock_1_svc(nlm_unlockargs * arg,struct svc_req * rqstp)570*86d7f5d3SJohn Marino nlm_unlock_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
571*86d7f5d3SJohn Marino {
572*86d7f5d3SJohn Marino 	static nlm_res res;
573*86d7f5d3SJohn Marino 	struct nlm4_lock arg4;
574*86d7f5d3SJohn Marino 
575*86d7f5d3SJohn Marino 	nlmtonlm4(&arg->alock, &arg4);
576*86d7f5d3SJohn Marino 
577*86d7f5d3SJohn Marino 	if (debug_level)
578*86d7f5d3SJohn Marino 		log_from_addr("nlm_unlock", rqstp);
579*86d7f5d3SJohn Marino 
580*86d7f5d3SJohn Marino 	res.stat.stat = unlock(&arg4, 0);
581*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
582*86d7f5d3SJohn Marino 
583*86d7f5d3SJohn Marino 	return (&res);
584*86d7f5d3SJohn Marino }
585*86d7f5d3SJohn Marino 
586*86d7f5d3SJohn Marino void *
nlm_unlock_msg_1_svc(nlm_unlockargs * arg,struct svc_req * rqstp)587*86d7f5d3SJohn Marino nlm_unlock_msg_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
588*86d7f5d3SJohn Marino {
589*86d7f5d3SJohn Marino 	static nlm_res res;
590*86d7f5d3SJohn Marino 	struct nlm4_lock arg4;
591*86d7f5d3SJohn Marino 
592*86d7f5d3SJohn Marino 	nlmtonlm4(&arg->alock, &arg4);
593*86d7f5d3SJohn Marino 
594*86d7f5d3SJohn Marino 	if (debug_level)
595*86d7f5d3SJohn Marino 		log_from_addr("nlm_unlock_msg", rqstp);
596*86d7f5d3SJohn Marino 
597*86d7f5d3SJohn Marino 	res.stat.stat = unlock(&arg4, 0);
598*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
599*86d7f5d3SJohn Marino 
600*86d7f5d3SJohn Marino 	transmit_result(NLM_UNLOCK_RES, &res, getrpcaddr(rqstp));
601*86d7f5d3SJohn Marino 	return (NULL);
602*86d7f5d3SJohn Marino }
603*86d7f5d3SJohn Marino 
604*86d7f5d3SJohn Marino /* ------------------------------------------------------------------------- */
605*86d7f5d3SJohn Marino /*
606*86d7f5d3SJohn Marino  * Client-side pseudo-RPCs for results.  Note that for the client there
607*86d7f5d3SJohn Marino  * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
608*86d7f5d3SJohn Marino  * version returns the results in the RPC result, and so the client
609*86d7f5d3SJohn Marino  * does not normally receive incoming RPCs.
610*86d7f5d3SJohn Marino  *
611*86d7f5d3SJohn Marino  * The exception to this is nlm_granted(), which is genuinely an RPC
612*86d7f5d3SJohn Marino  * call from the server to the client - a 'call-back' in normal procedure
613*86d7f5d3SJohn Marino  * call terms.
614*86d7f5d3SJohn Marino  */
615*86d7f5d3SJohn Marino 
616*86d7f5d3SJohn Marino /* nlm_granted ------------------------------------------------------------- */
617*86d7f5d3SJohn Marino /*
618*86d7f5d3SJohn Marino  * Purpose:	Receive notification that formerly blocked lock now granted
619*86d7f5d3SJohn Marino  * Returns:	always success ('granted')
620*86d7f5d3SJohn Marino  * Notes:
621*86d7f5d3SJohn Marino  */
622*86d7f5d3SJohn Marino nlm_res *
nlm_granted_1_svc(nlm_testargs * arg,struct svc_req * rqstp)623*86d7f5d3SJohn Marino nlm_granted_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
624*86d7f5d3SJohn Marino {
625*86d7f5d3SJohn Marino 	static nlm_res res;
626*86d7f5d3SJohn Marino 
627*86d7f5d3SJohn Marino 	if (debug_level)
628*86d7f5d3SJohn Marino 		log_from_addr("nlm_granted", rqstp);
629*86d7f5d3SJohn Marino 
630*86d7f5d3SJohn Marino 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
631*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
632*86d7f5d3SJohn Marino 
633*86d7f5d3SJohn Marino 	res.stat.stat = nlm_granted;
634*86d7f5d3SJohn Marino 	return (&res);
635*86d7f5d3SJohn Marino }
636*86d7f5d3SJohn Marino 
637*86d7f5d3SJohn Marino void *
nlm_granted_msg_1_svc(nlm_testargs * arg,struct svc_req * rqstp)638*86d7f5d3SJohn Marino nlm_granted_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
639*86d7f5d3SJohn Marino {
640*86d7f5d3SJohn Marino 	static nlm_res res;
641*86d7f5d3SJohn Marino 
642*86d7f5d3SJohn Marino 	if (debug_level)
643*86d7f5d3SJohn Marino 		log_from_addr("nlm_granted_msg", rqstp);
644*86d7f5d3SJohn Marino 
645*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
646*86d7f5d3SJohn Marino 	res.stat.stat = nlm_granted;
647*86d7f5d3SJohn Marino 	transmit_result(NLM_GRANTED_RES, &res,
648*86d7f5d3SJohn Marino 	    (struct sockaddr *)svc_getcaller(rqstp->rq_xprt));
649*86d7f5d3SJohn Marino 	return (NULL);
650*86d7f5d3SJohn Marino }
651*86d7f5d3SJohn Marino 
652*86d7f5d3SJohn Marino /* nlm_test_res ------------------------------------------------------------ */
653*86d7f5d3SJohn Marino /*
654*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_test_msg() call
655*86d7f5d3SJohn Marino  * Returns:	Nothing
656*86d7f5d3SJohn Marino  */
657*86d7f5d3SJohn Marino void *
nlm_test_res_1_svc(nlm_testres * arg,struct svc_req * rqstp)658*86d7f5d3SJohn Marino nlm_test_res_1_svc(nlm_testres *arg, struct svc_req *rqstp)
659*86d7f5d3SJohn Marino {
660*86d7f5d3SJohn Marino 	if (debug_level)
661*86d7f5d3SJohn Marino 		log_from_addr("nlm_test_res", rqstp);
662*86d7f5d3SJohn Marino 	return (NULL);
663*86d7f5d3SJohn Marino }
664*86d7f5d3SJohn Marino 
665*86d7f5d3SJohn Marino /* nlm_lock_res ------------------------------------------------------------ */
666*86d7f5d3SJohn Marino /*
667*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_lock_msg() call
668*86d7f5d3SJohn Marino  * Returns:	Nothing
669*86d7f5d3SJohn Marino  */
670*86d7f5d3SJohn Marino void *
nlm_lock_res_1_svc(nlm_res * arg,struct svc_req * rqstp)671*86d7f5d3SJohn Marino nlm_lock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
672*86d7f5d3SJohn Marino {
673*86d7f5d3SJohn Marino 	if (debug_level)
674*86d7f5d3SJohn Marino 		log_from_addr("nlm_lock_res", rqstp);
675*86d7f5d3SJohn Marino 
676*86d7f5d3SJohn Marino 	return (NULL);
677*86d7f5d3SJohn Marino }
678*86d7f5d3SJohn Marino 
679*86d7f5d3SJohn Marino /* nlm_cancel_res ---------------------------------------------------------- */
680*86d7f5d3SJohn Marino /*
681*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_cancel_msg() call
682*86d7f5d3SJohn Marino  * Returns:	Nothing
683*86d7f5d3SJohn Marino  */
684*86d7f5d3SJohn Marino void *
nlm_cancel_res_1_svc(nlm_res * arg __unused,struct svc_req * rqstp)685*86d7f5d3SJohn Marino nlm_cancel_res_1_svc(nlm_res *arg __unused, struct svc_req *rqstp)
686*86d7f5d3SJohn Marino {
687*86d7f5d3SJohn Marino 	if (debug_level)
688*86d7f5d3SJohn Marino 		log_from_addr("nlm_cancel_res", rqstp);
689*86d7f5d3SJohn Marino 	return (NULL);
690*86d7f5d3SJohn Marino }
691*86d7f5d3SJohn Marino 
692*86d7f5d3SJohn Marino /* nlm_unlock_res ---------------------------------------------------------- */
693*86d7f5d3SJohn Marino /*
694*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_unlock_msg() call
695*86d7f5d3SJohn Marino  * Returns:	Nothing
696*86d7f5d3SJohn Marino  */
697*86d7f5d3SJohn Marino void *
nlm_unlock_res_1_svc(nlm_res * arg,struct svc_req * rqstp)698*86d7f5d3SJohn Marino nlm_unlock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
699*86d7f5d3SJohn Marino {
700*86d7f5d3SJohn Marino 	if (debug_level)
701*86d7f5d3SJohn Marino 		log_from_addr("nlm_unlock_res", rqstp);
702*86d7f5d3SJohn Marino 	return (NULL);
703*86d7f5d3SJohn Marino }
704*86d7f5d3SJohn Marino 
705*86d7f5d3SJohn Marino /* nlm_granted_res --------------------------------------------------------- */
706*86d7f5d3SJohn Marino /*
707*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_granted_msg() call
708*86d7f5d3SJohn Marino  * Returns:	Nothing
709*86d7f5d3SJohn Marino  */
710*86d7f5d3SJohn Marino void *
nlm_granted_res_1_svc(nlm_res * arg __unused,struct svc_req * rqstp)711*86d7f5d3SJohn Marino nlm_granted_res_1_svc(nlm_res *arg __unused, struct svc_req *rqstp)
712*86d7f5d3SJohn Marino {
713*86d7f5d3SJohn Marino 	if (debug_level)
714*86d7f5d3SJohn Marino 		log_from_addr("nlm_granted_res", rqstp);
715*86d7f5d3SJohn Marino 	return (NULL);
716*86d7f5d3SJohn Marino }
717*86d7f5d3SJohn Marino 
718*86d7f5d3SJohn Marino /* ------------------------------------------------------------------------- */
719*86d7f5d3SJohn Marino /*
720*86d7f5d3SJohn Marino  * Calls for PCNFS locking (aka non-monitored locking, no involvement
721*86d7f5d3SJohn Marino  * of rpc.statd).
722*86d7f5d3SJohn Marino  *
723*86d7f5d3SJohn Marino  * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
724*86d7f5d3SJohn Marino  */
725*86d7f5d3SJohn Marino 
726*86d7f5d3SJohn Marino /* nlm_share --------------------------------------------------------------- */
727*86d7f5d3SJohn Marino /*
728*86d7f5d3SJohn Marino  * Purpose:	Establish a DOS-style lock
729*86d7f5d3SJohn Marino  * Returns:	success or failure
730*86d7f5d3SJohn Marino  * Notes:	Blocking locks are not supported - client is expected
731*86d7f5d3SJohn Marino  *		to retry if required.
732*86d7f5d3SJohn Marino  */
733*86d7f5d3SJohn Marino nlm_shareres *
nlm_share_3_svc(nlm_shareargs * arg,struct svc_req * rqstp)734*86d7f5d3SJohn Marino nlm_share_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
735*86d7f5d3SJohn Marino {
736*86d7f5d3SJohn Marino 	static nlm_shareres res;
737*86d7f5d3SJohn Marino 
738*86d7f5d3SJohn Marino 	if (debug_level)
739*86d7f5d3SJohn Marino 		log_from_addr("nlm_share", rqstp);
740*86d7f5d3SJohn Marino 
741*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
742*86d7f5d3SJohn Marino 	res.stat = nlm_granted;
743*86d7f5d3SJohn Marino 	res.sequence = 1234356;	/* X/Open says this field is ignored? */
744*86d7f5d3SJohn Marino 	return (&res);
745*86d7f5d3SJohn Marino }
746*86d7f5d3SJohn Marino 
747*86d7f5d3SJohn Marino /* nlm_unshare ------------------------------------------------------------ */
748*86d7f5d3SJohn Marino /*
749*86d7f5d3SJohn Marino  * Purpose:	Release a DOS-style lock
750*86d7f5d3SJohn Marino  * Returns:	nlm_granted, unless in grace period
751*86d7f5d3SJohn Marino  * Notes:
752*86d7f5d3SJohn Marino  */
753*86d7f5d3SJohn Marino nlm_shareres *
nlm_unshare_3_svc(nlm_shareargs * arg,struct svc_req * rqstp)754*86d7f5d3SJohn Marino nlm_unshare_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
755*86d7f5d3SJohn Marino {
756*86d7f5d3SJohn Marino 	static nlm_shareres res;
757*86d7f5d3SJohn Marino 
758*86d7f5d3SJohn Marino 	if (debug_level)
759*86d7f5d3SJohn Marino 		log_from_addr("nlm_unshare", rqstp);
760*86d7f5d3SJohn Marino 
761*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
762*86d7f5d3SJohn Marino 	res.stat = nlm_granted;
763*86d7f5d3SJohn Marino 	res.sequence = 1234356;	/* X/Open says this field is ignored? */
764*86d7f5d3SJohn Marino 	return (&res);
765*86d7f5d3SJohn Marino }
766*86d7f5d3SJohn Marino 
767*86d7f5d3SJohn Marino /* nlm_nm_lock ------------------------------------------------------------ */
768*86d7f5d3SJohn Marino /*
769*86d7f5d3SJohn Marino  * Purpose:	non-monitored version of nlm_lock()
770*86d7f5d3SJohn Marino  * Returns:	as for nlm_lock()
771*86d7f5d3SJohn Marino  * Notes:	These locks are in the same style as the standard nlm_lock,
772*86d7f5d3SJohn Marino  *		but the rpc.statd should not be called to establish a
773*86d7f5d3SJohn Marino  *		monitor for the client machine, since that machine is
774*86d7f5d3SJohn Marino  *		declared not to be running a rpc.statd, and so would not
775*86d7f5d3SJohn Marino  *		respond to the statd protocol.
776*86d7f5d3SJohn Marino  */
777*86d7f5d3SJohn Marino nlm_res *
nlm_nm_lock_3_svc(nlm_lockargs * arg,struct svc_req * rqstp)778*86d7f5d3SJohn Marino nlm_nm_lock_3_svc(nlm_lockargs *arg, struct svc_req *rqstp)
779*86d7f5d3SJohn Marino {
780*86d7f5d3SJohn Marino 	static nlm_res res;
781*86d7f5d3SJohn Marino 
782*86d7f5d3SJohn Marino 	if (debug_level)
783*86d7f5d3SJohn Marino 		log_from_addr("nlm_nm_lock", rqstp);
784*86d7f5d3SJohn Marino 
785*86d7f5d3SJohn Marino 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
786*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
787*86d7f5d3SJohn Marino 	res.stat.stat = nlm_granted;
788*86d7f5d3SJohn Marino 	return (&res);
789*86d7f5d3SJohn Marino }
790*86d7f5d3SJohn Marino 
791*86d7f5d3SJohn Marino /* nlm_free_all ------------------------------------------------------------ */
792*86d7f5d3SJohn Marino /*
793*86d7f5d3SJohn Marino  * Purpose:	Release all locks held by a named client
794*86d7f5d3SJohn Marino  * Returns:	Nothing
795*86d7f5d3SJohn Marino  * Notes:	Potential denial of service security problem here - the
796*86d7f5d3SJohn Marino  *		locks to be released are specified by a host name, independent
797*86d7f5d3SJohn Marino  *		of the address from which the request has arrived.
798*86d7f5d3SJohn Marino  *		Should probably be rejected if the named host has been
799*86d7f5d3SJohn Marino  *		using monitored locks.
800*86d7f5d3SJohn Marino  */
801*86d7f5d3SJohn Marino void *
nlm_free_all_3_svc(nlm_notify * arg __unused,struct svc_req * rqstp)802*86d7f5d3SJohn Marino nlm_free_all_3_svc(nlm_notify *arg __unused, struct svc_req *rqstp)
803*86d7f5d3SJohn Marino {
804*86d7f5d3SJohn Marino 	static char dummy;
805*86d7f5d3SJohn Marino 
806*86d7f5d3SJohn Marino 	if (debug_level)
807*86d7f5d3SJohn Marino 		log_from_addr("nlm_free_all", rqstp);
808*86d7f5d3SJohn Marino 	return (&dummy);
809*86d7f5d3SJohn Marino }
810*86d7f5d3SJohn Marino 
811*86d7f5d3SJohn Marino /* calls for nlm version 4 (NFSv3) */
812*86d7f5d3SJohn Marino /* nlm_test ---------------------------------------------------------------- */
813*86d7f5d3SJohn Marino /*
814*86d7f5d3SJohn Marino  * Purpose:	Test whether a specified lock would be granted if requested
815*86d7f5d3SJohn Marino  * Returns:	nlm_granted (or error code)
816*86d7f5d3SJohn Marino  * Notes:
817*86d7f5d3SJohn Marino  */
818*86d7f5d3SJohn Marino nlm4_testres *
nlm4_test_4_svc(nlm4_testargs * arg,struct svc_req * rqstp)819*86d7f5d3SJohn Marino nlm4_test_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
820*86d7f5d3SJohn Marino {
821*86d7f5d3SJohn Marino 	static nlm4_testres res;
822*86d7f5d3SJohn Marino 	struct nlm4_holder *holder;
823*86d7f5d3SJohn Marino 
824*86d7f5d3SJohn Marino 	if (debug_level)
825*86d7f5d3SJohn Marino 		log_from_addr("nlm4_test", rqstp);
826*86d7f5d3SJohn Marino 
827*86d7f5d3SJohn Marino 	holder = testlock(&arg->alock, LOCK_V4);
828*86d7f5d3SJohn Marino 
829*86d7f5d3SJohn Marino 	/*
830*86d7f5d3SJohn Marino 	 * Copy the cookie from the argument into the result.  Note that this
831*86d7f5d3SJohn Marino 	 * is slightly hazardous, as the structure contains a pointer to a
832*86d7f5d3SJohn Marino 	 * malloc()ed buffer that will get freed by the caller.  However, the
833*86d7f5d3SJohn Marino 	 * main function transmits the result before freeing the argument
834*86d7f5d3SJohn Marino 	 * so it is in fact safe.
835*86d7f5d3SJohn Marino 	 */
836*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
837*86d7f5d3SJohn Marino 	if (holder == NULL) {
838*86d7f5d3SJohn Marino 		res.stat.stat = nlm4_granted;
839*86d7f5d3SJohn Marino 	} else {
840*86d7f5d3SJohn Marino 		res.stat.stat = nlm4_denied;
841*86d7f5d3SJohn Marino 		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
842*86d7f5d3SJohn Marino 		    sizeof(struct nlm4_holder));
843*86d7f5d3SJohn Marino 	}
844*86d7f5d3SJohn Marino 	return (&res);
845*86d7f5d3SJohn Marino }
846*86d7f5d3SJohn Marino 
847*86d7f5d3SJohn Marino void *
nlm4_test_msg_4_svc(nlm4_testargs * arg,struct svc_req * rqstp)848*86d7f5d3SJohn Marino nlm4_test_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
849*86d7f5d3SJohn Marino {
850*86d7f5d3SJohn Marino 	nlm4_testres res;
851*86d7f5d3SJohn Marino 	static char dummy;
852*86d7f5d3SJohn Marino 	struct sockaddr *addr;
853*86d7f5d3SJohn Marino 	CLIENT *cli;
854*86d7f5d3SJohn Marino 	int success;
855*86d7f5d3SJohn Marino 	struct timeval timeo;
856*86d7f5d3SJohn Marino 	struct nlm4_holder *holder;
857*86d7f5d3SJohn Marino 
858*86d7f5d3SJohn Marino 	if (debug_level)
859*86d7f5d3SJohn Marino 		log_from_addr("nlm4_test_msg", rqstp);
860*86d7f5d3SJohn Marino 
861*86d7f5d3SJohn Marino 	holder = testlock(&arg->alock, LOCK_V4);
862*86d7f5d3SJohn Marino 
863*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
864*86d7f5d3SJohn Marino 	if (holder == NULL) {
865*86d7f5d3SJohn Marino 		res.stat.stat = nlm4_granted;
866*86d7f5d3SJohn Marino 	} else {
867*86d7f5d3SJohn Marino 		res.stat.stat = nlm4_denied;
868*86d7f5d3SJohn Marino 		memcpy(&res.stat.nlm4_testrply_u.holder, holder,
869*86d7f5d3SJohn Marino 		    sizeof(struct nlm4_holder));
870*86d7f5d3SJohn Marino 	}
871*86d7f5d3SJohn Marino 
872*86d7f5d3SJohn Marino 	/*
873*86d7f5d3SJohn Marino 	 * nlm_test has different result type to the other operations, so
874*86d7f5d3SJohn Marino 	 * can't use transmit4_result() in this case
875*86d7f5d3SJohn Marino 	 */
876*86d7f5d3SJohn Marino 	addr = svc_getrpccaller(rqstp->rq_xprt)->buf;
877*86d7f5d3SJohn Marino 	if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
878*86d7f5d3SJohn Marino 		timeo.tv_sec = 0; /* No timeout - not expecting response */
879*86d7f5d3SJohn Marino 		timeo.tv_usec = 0;
880*86d7f5d3SJohn Marino 
881*86d7f5d3SJohn Marino 		success = clnt_call(cli, NLM4_TEST_RES,
882*86d7f5d3SJohn Marino 		    (xdrproc_t)xdr_nlm4_testres, &res,
883*86d7f5d3SJohn Marino 		    (xdrproc_t)xdr_void, &dummy, timeo);
884*86d7f5d3SJohn Marino 
885*86d7f5d3SJohn Marino 		if (debug_level > 2)
886*86d7f5d3SJohn Marino 			syslog(LOG_DEBUG, "clnt_call returns %d", success);
887*86d7f5d3SJohn Marino 	}
888*86d7f5d3SJohn Marino 	return (NULL);
889*86d7f5d3SJohn Marino }
890*86d7f5d3SJohn Marino 
891*86d7f5d3SJohn Marino /* nlm_lock ---------------------------------------------------------------- */
892*86d7f5d3SJohn Marino /*
893*86d7f5d3SJohn Marino  * Purposes:	Establish a lock
894*86d7f5d3SJohn Marino  * Returns:	granted, denied or blocked
895*86d7f5d3SJohn Marino  * Notes:	*** grace period support missing
896*86d7f5d3SJohn Marino  */
897*86d7f5d3SJohn Marino nlm4_res *
nlm4_lock_4_svc(nlm4_lockargs * arg,struct svc_req * rqstp)898*86d7f5d3SJohn Marino nlm4_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
899*86d7f5d3SJohn Marino {
900*86d7f5d3SJohn Marino 	static nlm4_res res;
901*86d7f5d3SJohn Marino 
902*86d7f5d3SJohn Marino 	if (debug_level)
903*86d7f5d3SJohn Marino 		log_from_addr("nlm4_lock", rqstp);
904*86d7f5d3SJohn Marino 
905*86d7f5d3SJohn Marino 	/* copy cookie from arg to result.  See comment in nlm_test_4() */
906*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
907*86d7f5d3SJohn Marino 
908*86d7f5d3SJohn Marino 	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_V4);
909*86d7f5d3SJohn Marino 	return (&res);
910*86d7f5d3SJohn Marino }
911*86d7f5d3SJohn Marino 
912*86d7f5d3SJohn Marino void *
nlm4_lock_msg_4_svc(nlm4_lockargs * arg,struct svc_req * rqstp)913*86d7f5d3SJohn Marino nlm4_lock_msg_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
914*86d7f5d3SJohn Marino {
915*86d7f5d3SJohn Marino 	static nlm4_res res;
916*86d7f5d3SJohn Marino 
917*86d7f5d3SJohn Marino 	if (debug_level)
918*86d7f5d3SJohn Marino 		log_from_addr("nlm4_lock_msg", rqstp);
919*86d7f5d3SJohn Marino 
920*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
921*86d7f5d3SJohn Marino 	res.stat.stat = getlock(arg, rqstp, LOCK_MON | LOCK_ASYNC | LOCK_V4);
922*86d7f5d3SJohn Marino 	transmit4_result(NLM4_LOCK_RES, &res, getrpcaddr(rqstp));
923*86d7f5d3SJohn Marino 
924*86d7f5d3SJohn Marino 	return (NULL);
925*86d7f5d3SJohn Marino }
926*86d7f5d3SJohn Marino 
927*86d7f5d3SJohn Marino /* nlm_cancel -------------------------------------------------------------- */
928*86d7f5d3SJohn Marino /*
929*86d7f5d3SJohn Marino  * Purpose:	Cancel a blocked lock request
930*86d7f5d3SJohn Marino  * Returns:	granted or denied
931*86d7f5d3SJohn Marino  * Notes:
932*86d7f5d3SJohn Marino  */
933*86d7f5d3SJohn Marino nlm4_res *
nlm4_cancel_4_svc(nlm4_cancargs * arg,struct svc_req * rqstp)934*86d7f5d3SJohn Marino nlm4_cancel_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
935*86d7f5d3SJohn Marino {
936*86d7f5d3SJohn Marino 	static nlm4_res res;
937*86d7f5d3SJohn Marino 
938*86d7f5d3SJohn Marino 	if (debug_level)
939*86d7f5d3SJohn Marino 		log_from_addr("nlm4_cancel", rqstp);
940*86d7f5d3SJohn Marino 
941*86d7f5d3SJohn Marino 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
942*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
943*86d7f5d3SJohn Marino 
944*86d7f5d3SJohn Marino 	/*
945*86d7f5d3SJohn Marino 	 * Since at present we never return 'nlm_blocked', there can never be
946*86d7f5d3SJohn Marino 	 * a lock to cancel, so this call always fails.
947*86d7f5d3SJohn Marino 	 */
948*86d7f5d3SJohn Marino 	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL);
949*86d7f5d3SJohn Marino 	return (&res);
950*86d7f5d3SJohn Marino }
951*86d7f5d3SJohn Marino 
952*86d7f5d3SJohn Marino void *
nlm4_cancel_msg_4_svc(nlm4_cancargs * arg,struct svc_req * rqstp)953*86d7f5d3SJohn Marino nlm4_cancel_msg_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
954*86d7f5d3SJohn Marino {
955*86d7f5d3SJohn Marino 	static nlm4_res res;
956*86d7f5d3SJohn Marino 
957*86d7f5d3SJohn Marino 	if (debug_level)
958*86d7f5d3SJohn Marino 		log_from_addr("nlm4_cancel_msg", rqstp);
959*86d7f5d3SJohn Marino 
960*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
961*86d7f5d3SJohn Marino 	/*
962*86d7f5d3SJohn Marino 	 * Since at present we never return 'nlm_blocked', there can never be
963*86d7f5d3SJohn Marino 	 * a lock to cancel, so this call always fails.
964*86d7f5d3SJohn Marino 	 */
965*86d7f5d3SJohn Marino 	res.stat.stat = unlock(&arg->alock, LOCK_CANCEL | LOCK_V4);
966*86d7f5d3SJohn Marino 	transmit4_result(NLM4_CANCEL_RES, &res, getrpcaddr(rqstp));
967*86d7f5d3SJohn Marino 	return (NULL);
968*86d7f5d3SJohn Marino }
969*86d7f5d3SJohn Marino 
970*86d7f5d3SJohn Marino /* nlm_unlock -------------------------------------------------------------- */
971*86d7f5d3SJohn Marino /*
972*86d7f5d3SJohn Marino  * Purpose:	Release an existing lock
973*86d7f5d3SJohn Marino  * Returns:	Always granted, unless during grace period
974*86d7f5d3SJohn Marino  * Notes:	"no such lock" error condition is ignored, as the
975*86d7f5d3SJohn Marino  *		protocol uses unreliable UDP datagrams, and may well
976*86d7f5d3SJohn Marino  *		re-try an unlock that has already succeeded.
977*86d7f5d3SJohn Marino  */
978*86d7f5d3SJohn Marino nlm4_res *
nlm4_unlock_4_svc(nlm4_unlockargs * arg,struct svc_req * rqstp)979*86d7f5d3SJohn Marino nlm4_unlock_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
980*86d7f5d3SJohn Marino {
981*86d7f5d3SJohn Marino 	static nlm4_res res;
982*86d7f5d3SJohn Marino 
983*86d7f5d3SJohn Marino 	if (debug_level)
984*86d7f5d3SJohn Marino 		log_from_addr("nlm4_unlock", rqstp);
985*86d7f5d3SJohn Marino 
986*86d7f5d3SJohn Marino 	res.stat.stat = unlock(&arg->alock, LOCK_V4);
987*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
988*86d7f5d3SJohn Marino 
989*86d7f5d3SJohn Marino 	return (&res);
990*86d7f5d3SJohn Marino }
991*86d7f5d3SJohn Marino 
992*86d7f5d3SJohn Marino void *
nlm4_unlock_msg_4_svc(nlm4_unlockargs * arg,struct svc_req * rqstp)993*86d7f5d3SJohn Marino nlm4_unlock_msg_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
994*86d7f5d3SJohn Marino {
995*86d7f5d3SJohn Marino 	static nlm4_res res;
996*86d7f5d3SJohn Marino 
997*86d7f5d3SJohn Marino 	if (debug_level)
998*86d7f5d3SJohn Marino 		log_from_addr("nlm4_unlock_msg", rqstp);
999*86d7f5d3SJohn Marino 
1000*86d7f5d3SJohn Marino 	res.stat.stat = unlock(&arg->alock, LOCK_V4);
1001*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
1002*86d7f5d3SJohn Marino 
1003*86d7f5d3SJohn Marino 	transmit4_result(NLM4_UNLOCK_RES, &res, getrpcaddr(rqstp));
1004*86d7f5d3SJohn Marino 	return (NULL);
1005*86d7f5d3SJohn Marino }
1006*86d7f5d3SJohn Marino 
1007*86d7f5d3SJohn Marino /* ------------------------------------------------------------------------- */
1008*86d7f5d3SJohn Marino /*
1009*86d7f5d3SJohn Marino  * Client-side pseudo-RPCs for results.  Note that for the client there
1010*86d7f5d3SJohn Marino  * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
1011*86d7f5d3SJohn Marino  * version returns the results in the RPC result, and so the client
1012*86d7f5d3SJohn Marino  * does not normally receive incoming RPCs.
1013*86d7f5d3SJohn Marino  *
1014*86d7f5d3SJohn Marino  * The exception to this is nlm_granted(), which is genuinely an RPC
1015*86d7f5d3SJohn Marino  * call from the server to the client - a 'call-back' in normal procedure
1016*86d7f5d3SJohn Marino  * call terms.
1017*86d7f5d3SJohn Marino  */
1018*86d7f5d3SJohn Marino 
1019*86d7f5d3SJohn Marino /* nlm_granted ------------------------------------------------------------- */
1020*86d7f5d3SJohn Marino /*
1021*86d7f5d3SJohn Marino  * Purpose:	Receive notification that formerly blocked lock now granted
1022*86d7f5d3SJohn Marino  * Returns:	always success ('granted')
1023*86d7f5d3SJohn Marino  * Notes:
1024*86d7f5d3SJohn Marino  */
1025*86d7f5d3SJohn Marino nlm4_res *
nlm4_granted_4_svc(nlm4_testargs * arg,struct svc_req * rqstp)1026*86d7f5d3SJohn Marino nlm4_granted_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
1027*86d7f5d3SJohn Marino {
1028*86d7f5d3SJohn Marino 	static nlm4_res res;
1029*86d7f5d3SJohn Marino 
1030*86d7f5d3SJohn Marino 	if (debug_level)
1031*86d7f5d3SJohn Marino 		log_from_addr("nlm4_granted", rqstp);
1032*86d7f5d3SJohn Marino 
1033*86d7f5d3SJohn Marino 	/* copy cookie from arg to result.  See comment in nlm_test_1() */
1034*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
1035*86d7f5d3SJohn Marino 
1036*86d7f5d3SJohn Marino 	res.stat.stat = nlm4_granted;
1037*86d7f5d3SJohn Marino 	return (&res);
1038*86d7f5d3SJohn Marino }
1039*86d7f5d3SJohn Marino 
1040*86d7f5d3SJohn Marino void *
nlm4_granted_msg_4_svc(nlm4_testargs * arg,struct svc_req * rqstp)1041*86d7f5d3SJohn Marino nlm4_granted_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
1042*86d7f5d3SJohn Marino {
1043*86d7f5d3SJohn Marino 	static nlm4_res res;
1044*86d7f5d3SJohn Marino 
1045*86d7f5d3SJohn Marino 	if (debug_level)
1046*86d7f5d3SJohn Marino 		log_from_addr("nlm4_granted_msg", rqstp);
1047*86d7f5d3SJohn Marino 
1048*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
1049*86d7f5d3SJohn Marino 	res.stat.stat = nlm4_granted;
1050*86d7f5d3SJohn Marino 	transmit4_result(NLM4_GRANTED_RES, &res,
1051*86d7f5d3SJohn Marino 	    (struct sockaddr *)svc_getrpccaller(rqstp->rq_xprt)->buf);
1052*86d7f5d3SJohn Marino 	return (NULL);
1053*86d7f5d3SJohn Marino }
1054*86d7f5d3SJohn Marino 
1055*86d7f5d3SJohn Marino /* nlm_test_res ------------------------------------------------------------ */
1056*86d7f5d3SJohn Marino /*
1057*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_test_msg() call
1058*86d7f5d3SJohn Marino  * Returns:	Nothing
1059*86d7f5d3SJohn Marino  */
1060*86d7f5d3SJohn Marino void *
nlm4_test_res_4_svc(nlm4_testres * arg,struct svc_req * rqstp)1061*86d7f5d3SJohn Marino nlm4_test_res_4_svc(nlm4_testres *arg, struct svc_req *rqstp)
1062*86d7f5d3SJohn Marino {
1063*86d7f5d3SJohn Marino 	if (debug_level)
1064*86d7f5d3SJohn Marino 		log_from_addr("nlm4_test_res", rqstp);
1065*86d7f5d3SJohn Marino 	return (NULL);
1066*86d7f5d3SJohn Marino }
1067*86d7f5d3SJohn Marino 
1068*86d7f5d3SJohn Marino /* nlm_lock_res ------------------------------------------------------------ */
1069*86d7f5d3SJohn Marino /*
1070*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_lock_msg() call
1071*86d7f5d3SJohn Marino  * Returns:	Nothing
1072*86d7f5d3SJohn Marino  */
1073*86d7f5d3SJohn Marino void *
nlm4_lock_res_4_svc(nlm4_res * arg,struct svc_req * rqstp)1074*86d7f5d3SJohn Marino nlm4_lock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
1075*86d7f5d3SJohn Marino {
1076*86d7f5d3SJohn Marino 	if (debug_level)
1077*86d7f5d3SJohn Marino 		log_from_addr("nlm4_lock_res", rqstp);
1078*86d7f5d3SJohn Marino 
1079*86d7f5d3SJohn Marino 	return (NULL);
1080*86d7f5d3SJohn Marino }
1081*86d7f5d3SJohn Marino 
1082*86d7f5d3SJohn Marino /* nlm_cancel_res ---------------------------------------------------------- */
1083*86d7f5d3SJohn Marino /*
1084*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_cancel_msg() call
1085*86d7f5d3SJohn Marino  * Returns:	Nothing
1086*86d7f5d3SJohn Marino  */
1087*86d7f5d3SJohn Marino void *
nlm4_cancel_res_4_svc(nlm4_res * arg __unused,struct svc_req * rqstp)1088*86d7f5d3SJohn Marino nlm4_cancel_res_4_svc(nlm4_res *arg __unused, struct svc_req *rqstp)
1089*86d7f5d3SJohn Marino {
1090*86d7f5d3SJohn Marino 	if (debug_level)
1091*86d7f5d3SJohn Marino 		log_from_addr("nlm4_cancel_res", rqstp);
1092*86d7f5d3SJohn Marino 	return (NULL);
1093*86d7f5d3SJohn Marino }
1094*86d7f5d3SJohn Marino 
1095*86d7f5d3SJohn Marino /* nlm_unlock_res ---------------------------------------------------------- */
1096*86d7f5d3SJohn Marino /*
1097*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_unlock_msg() call
1098*86d7f5d3SJohn Marino  * Returns:	Nothing
1099*86d7f5d3SJohn Marino  */
1100*86d7f5d3SJohn Marino void *
nlm4_unlock_res_4_svc(nlm4_res * arg __unused,struct svc_req * rqstp)1101*86d7f5d3SJohn Marino nlm4_unlock_res_4_svc(nlm4_res *arg __unused, struct svc_req *rqstp)
1102*86d7f5d3SJohn Marino {
1103*86d7f5d3SJohn Marino 	if (debug_level)
1104*86d7f5d3SJohn Marino 		log_from_addr("nlm4_unlock_res", rqstp);
1105*86d7f5d3SJohn Marino 	return (NULL);
1106*86d7f5d3SJohn Marino }
1107*86d7f5d3SJohn Marino 
1108*86d7f5d3SJohn Marino /* nlm_granted_res --------------------------------------------------------- */
1109*86d7f5d3SJohn Marino /*
1110*86d7f5d3SJohn Marino  * Purpose:	Accept result from earlier nlm_granted_msg() call
1111*86d7f5d3SJohn Marino  * Returns:	Nothing
1112*86d7f5d3SJohn Marino  */
1113*86d7f5d3SJohn Marino void *
nlm4_granted_res_4_svc(nlm4_res * arg,struct svc_req * rqstp)1114*86d7f5d3SJohn Marino nlm4_granted_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
1115*86d7f5d3SJohn Marino {
1116*86d7f5d3SJohn Marino 	if (debug_level)
1117*86d7f5d3SJohn Marino 		log_from_addr("nlm4_granted_res", rqstp);
1118*86d7f5d3SJohn Marino 	return (NULL);
1119*86d7f5d3SJohn Marino }
1120*86d7f5d3SJohn Marino 
1121*86d7f5d3SJohn Marino /* ------------------------------------------------------------------------- */
1122*86d7f5d3SJohn Marino /*
1123*86d7f5d3SJohn Marino  * Calls for PCNFS locking (aka non-monitored locking, no involvement
1124*86d7f5d3SJohn Marino  * of rpc.statd).
1125*86d7f5d3SJohn Marino  *
1126*86d7f5d3SJohn Marino  * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
1127*86d7f5d3SJohn Marino  */
1128*86d7f5d3SJohn Marino 
1129*86d7f5d3SJohn Marino /* nlm_share --------------------------------------------------------------- */
1130*86d7f5d3SJohn Marino /*
1131*86d7f5d3SJohn Marino  * Purpose:	Establish a DOS-style lock
1132*86d7f5d3SJohn Marino  * Returns:	success or failure
1133*86d7f5d3SJohn Marino  * Notes:	Blocking locks are not supported - client is expected
1134*86d7f5d3SJohn Marino  *		to retry if required.
1135*86d7f5d3SJohn Marino  */
1136*86d7f5d3SJohn Marino nlm4_shareres *
nlm4_share_4_svc(nlm4_shareargs * arg,struct svc_req * rqstp)1137*86d7f5d3SJohn Marino nlm4_share_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
1138*86d7f5d3SJohn Marino {
1139*86d7f5d3SJohn Marino 	static nlm4_shareres res;
1140*86d7f5d3SJohn Marino 
1141*86d7f5d3SJohn Marino 	if (debug_level)
1142*86d7f5d3SJohn Marino 		log_from_addr("nlm4_share", rqstp);
1143*86d7f5d3SJohn Marino 
1144*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
1145*86d7f5d3SJohn Marino 	res.stat = nlm4_granted;
1146*86d7f5d3SJohn Marino 	res.sequence = 1234356;	/* X/Open says this field is ignored? */
1147*86d7f5d3SJohn Marino 	return (&res);
1148*86d7f5d3SJohn Marino }
1149*86d7f5d3SJohn Marino 
1150*86d7f5d3SJohn Marino /* nlm4_unshare ------------------------------------------------------------ */
1151*86d7f5d3SJohn Marino /*
1152*86d7f5d3SJohn Marino  * Purpose:	Release a DOS-style lock
1153*86d7f5d3SJohn Marino  * Returns:	nlm_granted, unless in grace period
1154*86d7f5d3SJohn Marino  * Notes:
1155*86d7f5d3SJohn Marino  */
1156*86d7f5d3SJohn Marino nlm4_shareres *
nlm4_unshare_4_svc(nlm4_shareargs * arg,struct svc_req * rqstp)1157*86d7f5d3SJohn Marino nlm4_unshare_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
1158*86d7f5d3SJohn Marino {
1159*86d7f5d3SJohn Marino 	static nlm4_shareres res;
1160*86d7f5d3SJohn Marino 
1161*86d7f5d3SJohn Marino 	if (debug_level)
1162*86d7f5d3SJohn Marino 		log_from_addr("nlm_unshare", rqstp);
1163*86d7f5d3SJohn Marino 
1164*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
1165*86d7f5d3SJohn Marino 	res.stat = nlm4_granted;
1166*86d7f5d3SJohn Marino 	res.sequence = 1234356;	/* X/Open says this field is ignored? */
1167*86d7f5d3SJohn Marino 	return (&res);
1168*86d7f5d3SJohn Marino }
1169*86d7f5d3SJohn Marino 
1170*86d7f5d3SJohn Marino /* nlm4_nm_lock ------------------------------------------------------------ */
1171*86d7f5d3SJohn Marino /*
1172*86d7f5d3SJohn Marino  * Purpose:	non-monitored version of nlm4_lock()
1173*86d7f5d3SJohn Marino  * Returns:	as for nlm4_lock()
1174*86d7f5d3SJohn Marino  * Notes:	These locks are in the same style as the standard nlm4_lock,
1175*86d7f5d3SJohn Marino  *		but the rpc.statd should not be called to establish a
1176*86d7f5d3SJohn Marino  *		monitor for the client machine, since that machine is
1177*86d7f5d3SJohn Marino  *		declared not to be running a rpc.statd, and so would not
1178*86d7f5d3SJohn Marino  *		respond to the statd protocol.
1179*86d7f5d3SJohn Marino  */
1180*86d7f5d3SJohn Marino nlm4_res *
nlm4_nm_lock_4_svc(nlm4_lockargs * arg,struct svc_req * rqstp)1181*86d7f5d3SJohn Marino nlm4_nm_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
1182*86d7f5d3SJohn Marino {
1183*86d7f5d3SJohn Marino 	static nlm4_res res;
1184*86d7f5d3SJohn Marino 
1185*86d7f5d3SJohn Marino 	if (debug_level)
1186*86d7f5d3SJohn Marino 		log_from_addr("nlm4_nm_lock", rqstp);
1187*86d7f5d3SJohn Marino 
1188*86d7f5d3SJohn Marino 	/* copy cookie from arg to result.  See comment in nlm4_test_1() */
1189*86d7f5d3SJohn Marino 	res.cookie = arg->cookie;
1190*86d7f5d3SJohn Marino 	res.stat.stat = nlm4_granted;
1191*86d7f5d3SJohn Marino 	return (&res);
1192*86d7f5d3SJohn Marino }
1193*86d7f5d3SJohn Marino 
1194*86d7f5d3SJohn Marino /* nlm4_free_all ------------------------------------------------------------ */
1195*86d7f5d3SJohn Marino /*
1196*86d7f5d3SJohn Marino  * Purpose:	Release all locks held by a named client
1197*86d7f5d3SJohn Marino  * Returns:	Nothing
1198*86d7f5d3SJohn Marino  * Notes:	Potential denial of service security problem here - the
1199*86d7f5d3SJohn Marino  *		locks to be released are specified by a host name, independent
1200*86d7f5d3SJohn Marino  *		of the address from which the request has arrived.
1201*86d7f5d3SJohn Marino  *		Should probably be rejected if the named host has been
1202*86d7f5d3SJohn Marino  *		using monitored locks.
1203*86d7f5d3SJohn Marino  */
1204*86d7f5d3SJohn Marino void *
nlm4_free_all_4_svc(nlm_notify * arg,struct svc_req * rqstp)1205*86d7f5d3SJohn Marino nlm4_free_all_4_svc(nlm_notify *arg, struct svc_req *rqstp)
1206*86d7f5d3SJohn Marino {
1207*86d7f5d3SJohn Marino 	static char dummy;
1208*86d7f5d3SJohn Marino 
1209*86d7f5d3SJohn Marino 	if (debug_level)
1210*86d7f5d3SJohn Marino 		log_from_addr("nlm4_free_all", rqstp);
1211*86d7f5d3SJohn Marino 	return (&dummy);
1212*86d7f5d3SJohn Marino }
1213*86d7f5d3SJohn Marino 
1214*86d7f5d3SJohn Marino /* nlm_sm_notify --------------------------------------------------------- */
1215*86d7f5d3SJohn Marino /*
1216*86d7f5d3SJohn Marino  * Purpose:	called by rpc.statd when a monitored host state changes.
1217*86d7f5d3SJohn Marino  * Returns:	Nothing
1218*86d7f5d3SJohn Marino  */
1219*86d7f5d3SJohn Marino void *
nlm_sm_notify_0_svc(struct nlm_sm_status * arg,struct svc_req * rqstp __unused)1220*86d7f5d3SJohn Marino nlm_sm_notify_0_svc(struct nlm_sm_status *arg, struct svc_req *rqstp __unused)
1221*86d7f5d3SJohn Marino {
1222*86d7f5d3SJohn Marino 	static char dummy;
1223*86d7f5d3SJohn Marino 	notify(arg->mon_name, arg->state);
1224*86d7f5d3SJohn Marino 	return (&dummy);
1225*86d7f5d3SJohn Marino }
1226