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