No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / rpc.lockd / lock_proc.c
blobeda5e9a6e44d9f5c62c869b9e588e3269cd8363a
1 /* $NetBSD: lock_proc.c,v 1.8 2007/11/04 19:59:54 tron Exp $ */
3 /*
4 * Copyright (c) 1995
5 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
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.
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.
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __RCSID("$NetBSD: lock_proc.c,v 1.8 2007/11/04 19:59:54 tron Exp $");
39 #endif
41 #include <sys/param.h>
42 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
47 #include <netdb.h>
48 #include <stdio.h>
49 #include <string.h>
50 #include <syslog.h>
51 #include <netconfig.h>
53 #include <rpc/rpc.h>
54 #include <rpcsvc/sm_inter.h>
56 #include "lockd.h"
57 #include <rpcsvc/nlm_prot.h>
58 #include "lockd_lock.h"
61 #define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */
62 #define CLIENT_CACHE_LIFETIME 120 /* In seconds */
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 *);
68 /* log_from_addr ----------------------------------------------------------- */
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
75 static void
76 log_from_addr(const char *fun_name, struct svc_req *req)
78 struct sockaddr *addr;
79 char hostname_buf[NI_MAXHOST];
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;
86 syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
89 /* get_client -------------------------------------------------------------- */
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*.
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.
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).
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.
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;
123 static int
124 addrcmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
126 size_t len;
127 const void *p1, *p2;
129 if (sa1->sa_family != sa2->sa_family)
130 return -1;
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;
147 return memcmp(p1, p2, len);
150 CLIENT *
151 get_client(struct sockaddr *host_addr, rpcvers_t vers)
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];
160 (void)gettimeofday(&time_now, NULL);
163 * Search for the given client in the cache, zapping any expired
164 * entries that we happen to notice in passing.
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;
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;
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;
194 * Need a host string for clnt_tp_create. Use NI_NUMERICHOST
195 * to avoid DNS lookups.
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;
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;
221 client = clnt_tp_create(host, NLM_PROG, vers, nconf);
222 freenetconfigent(nconf);
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;
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;
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.)
243 retry_time.tv_sec = -1;
244 retry_time.tv_usec = -1;
245 clnt_control(client, CLSET_TIMEOUT, (char *)(void *)&retry_time);
247 if (debug_level > 3)
248 syslog(LOG_DEBUG, "Created CLIENT* for %s", host);
249 return client;
253 /* transmit_result --------------------------------------------------------- */
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
261 void
262 transmit_result(int opcode, nlm_res *result, struct sockaddr *addr)
264 static char dummy;
265 CLIENT *cli;
266 struct timeval timeo;
267 int success;
269 if ((cli = get_client(addr, NLM_VERS)) != NULL) {
270 timeo.tv_sec = 0; /* No timeout - not expecting response */
271 timeo.tv_usec = 0;
273 success = clnt_call(cli, (rpcproc_t)opcode, xdr_nlm_res,
274 result, xdr_void, &dummy, timeo);
276 if (debug_level > 2)
277 syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
278 success, clnt_sperrno(success));
281 /* transmit4_result --------------------------------------------------------- */
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
289 void
290 transmit4_result(int opcode, nlm4_res *result, struct sockaddr *addr)
292 static char dummy;
293 CLIENT *cli;
294 struct timeval timeo;
295 int success;
297 if ((cli = get_client(addr, NLM_VERS4)) != NULL) {
298 timeo.tv_sec = 0; /* No timeout - not expecting response */
299 timeo.tv_usec = 0;
301 success = clnt_call(cli, (rpcproc_t)opcode, xdr_nlm4_res,
302 result, xdr_void, &dummy, timeo);
304 if (debug_level > 2)
305 syslog(LOG_DEBUG, "clnt_call returns %d(%s)",
306 success, clnt_sperrno(success));
311 * converts a struct nlm_lock to struct nlm4_lock
313 static void
314 nlmtonlm4(struct nlm_lock *arg, struct nlm4_lock *arg4)
316 (void)memcpy(arg4, arg, sizeof(nlm_lock));
317 arg4->l_offset = arg->l_offset;
318 arg4->l_len = arg->l_len;
321 /* ------------------------------------------------------------------------- */
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.
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.
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.
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).
348 /* nlm_test ---------------------------------------------------------------- */
350 * Purpose: Test whether a specified lock would be granted if requested
351 * Returns: nlm_granted (or error code)
352 * Notes:
354 nlm_testres *
355 nlm_test_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
357 static nlm_testres result;
358 struct nlm4_lock arg4;
359 struct nlm4_holder *holder;
360 nlmtonlm4(&arg->alock, &arg4);
362 if (debug_level)
363 log_from_addr("nlm_test", rqstp);
365 holder = testlock(&arg4, 0);
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.
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;
385 return &result;
388 void *
389 nlm_test_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
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;
400 nlmtonlm4(&arg->alock, &arg4);
402 if (debug_level)
403 log_from_addr("nlm_test_msg", rqstp);
405 holder = testlock(&arg4, 0);
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;
421 * nlm_test has different result type to the other operations, so
422 * can't use transmit_result() in this case
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;
429 success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres,
430 &result, xdr_void, &dummy, timeo);
432 if (debug_level > 2)
433 syslog(LOG_DEBUG, "clnt_call returns %d", success);
435 return NULL;
438 /* nlm_lock ---------------------------------------------------------------- */
440 * Purposes: Establish a lock
441 * Returns: granted, denied or blocked
442 * Notes: *** grace period support missing
444 nlm_res *
445 nlm_lock_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
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;
456 if (debug_level)
457 log_from_addr("nlm_lock", rqstp);
459 /* copy cookie from arg to result. See comment in nlm_test_1() */
460 result.cookie = arg->cookie;
462 result.stat.stat = getlock(&arg4, rqstp, LOCK_MON);
463 return &result;
466 void *
467 nlm_lock_msg_1_svc(nlm_lockargs *arg, struct svc_req *rqstp)
469 static nlm_res result;
470 struct nlm4_lockargs arg4;
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;
479 if (debug_level)
480 log_from_addr("nlm_lock_msg", rqstp);
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));
487 return NULL;
490 /* nlm_cancel -------------------------------------------------------------- */
492 * Purpose: Cancel a blocked lock request
493 * Returns: granted or denied
494 * Notes:
496 nlm_res *
497 nlm_cancel_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
499 static nlm_res result;
500 struct nlm4_lock arg4;
502 nlmtonlm4(&arg->alock, &arg4);
504 if (debug_level)
505 log_from_addr("nlm_cancel", rqstp);
507 /* copy cookie from arg to result. See comment in nlm_test_1() */
508 result.cookie = arg->cookie;
511 * Since at present we never return 'nlm_blocked', there can never be
512 * a lock to cancel, so this call always fails.
514 result.stat.stat = unlock(&arg4, LOCK_CANCEL);
515 return &result;
518 void *
519 nlm_cancel_msg_1_svc(nlm_cancargs *arg, struct svc_req *rqstp)
521 static nlm_res result;
522 struct nlm4_lock arg4;
524 nlmtonlm4(&arg->alock, &arg4);
526 if (debug_level)
527 log_from_addr("nlm_cancel_msg", rqstp);
529 result.cookie = arg->cookie;
531 * Since at present we never return 'nlm_blocked', there can never be
532 * a lock to cancel, so this call always fails.
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;
540 /* nlm_unlock -------------------------------------------------------------- */
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.
548 nlm_res *
549 nlm_unlock_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
551 static nlm_res result;
552 struct nlm4_lock arg4;
554 nlmtonlm4(&arg->alock, &arg4);
556 if (debug_level)
557 log_from_addr("nlm_unlock", rqstp);
559 result.stat.stat = unlock(&arg4, 0);
560 result.cookie = arg->cookie;
562 return &result;
565 void *
566 nlm_unlock_msg_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp)
568 static nlm_res result;
569 struct nlm4_lock arg4;
571 nlmtonlm4(&arg->alock, &arg4);
573 if (debug_level)
574 log_from_addr("nlm_unlock_msg", rqstp);
576 result.stat.stat = unlock(&arg4, 0);
577 result.cookie = arg->cookie;
579 transmit_result(NLM_UNLOCK_RES, &result,
580 (struct sockaddr *)(void *)svc_getcaller(rqstp->rq_xprt));
581 return NULL;
584 /* ------------------------------------------------------------------------- */
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.
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.
596 /* nlm_granted ------------------------------------------------------------- */
598 * Purpose: Receive notification that formerly blocked lock now granted
599 * Returns: always success ('granted')
600 * Notes:
602 nlm_res *
603 nlm_granted_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
605 static nlm_res result;
607 if (debug_level)
608 log_from_addr("nlm_granted", rqstp);
610 /* copy cookie from arg to result. See comment in nlm_test_1() */
611 result.cookie = arg->cookie;
613 result.stat.stat = nlm_granted;
614 return &result;
617 void *
618 nlm_granted_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp)
620 static nlm_res result;
622 if (debug_level)
623 log_from_addr("nlm_granted_msg", rqstp);
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;
632 /* nlm_test_res ------------------------------------------------------------ */
634 * Purpose: Accept result from earlier nlm_test_msg() call
635 * Returns: Nothing
637 void *
638 /*ARGSUSED*/
639 nlm_test_res_1_svc(nlm_testres *arg, struct svc_req *rqstp)
641 if (debug_level)
642 log_from_addr("nlm_test_res", rqstp);
643 return NULL;
646 /* nlm_lock_res ------------------------------------------------------------ */
648 * Purpose: Accept result from earlier nlm_lock_msg() call
649 * Returns: Nothing
651 void *
652 /*ARGSUSED*/
653 nlm_lock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
655 if (debug_level)
656 log_from_addr("nlm_lock_res", rqstp);
658 return NULL;
661 /* nlm_cancel_res ---------------------------------------------------------- */
663 * Purpose: Accept result from earlier nlm_cancel_msg() call
664 * Returns: Nothing
666 void *
667 /*ARGSUSED*/
668 nlm_cancel_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
670 if (debug_level)
671 log_from_addr("nlm_cancel_res", rqstp);
672 return NULL;
675 /* nlm_unlock_res ---------------------------------------------------------- */
677 * Purpose: Accept result from earlier nlm_unlock_msg() call
678 * Returns: Nothing
680 void *
681 /*ARGSUSED*/
682 nlm_unlock_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
684 if (debug_level)
685 log_from_addr("nlm_unlock_res", rqstp);
686 return NULL;
689 /* nlm_granted_res --------------------------------------------------------- */
691 * Purpose: Accept result from earlier nlm_granted_msg() call
692 * Returns: Nothing
694 void *
695 /*ARGSUSED*/
696 nlm_granted_res_1_svc(nlm_res *arg, struct svc_req *rqstp)
698 if (debug_level)
699 log_from_addr("nlm_granted_res", rqstp);
700 return NULL;
703 /* ------------------------------------------------------------------------- */
705 * Calls for PCNFS locking (aka non-monitored locking, no involvement
706 * of rpc.statd).
708 * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
711 /* nlm_share --------------------------------------------------------------- */
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.
718 nlm_shareres *
719 nlm_share_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
721 static nlm_shareres result;
723 if (debug_level)
724 log_from_addr("nlm_share", rqstp);
726 result.cookie = arg->cookie;
727 result.stat = nlm_granted;
728 result.sequence = 1234356; /* X/Open says this field is ignored? */
729 return &result;
732 /* nlm_unshare ------------------------------------------------------------ */
734 * Purpose: Release a DOS-style lock
735 * Returns: nlm_granted, unless in grace period
736 * Notes:
738 nlm_shareres *
739 nlm_unshare_3_svc(nlm_shareargs *arg, struct svc_req *rqstp)
741 static nlm_shareres result;
743 if (debug_level)
744 log_from_addr("nlm_unshare", rqstp);
746 result.cookie = arg->cookie;
747 result.stat = nlm_granted;
748 result.sequence = 1234356; /* X/Open says this field is ignored? */
749 return &result;
752 /* nlm_nm_lock ------------------------------------------------------------ */
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.
762 nlm_res *
763 nlm_nm_lock_3_svc(nlm_lockargs *arg, struct svc_req *rqstp)
765 static nlm_res result;
767 if (debug_level)
768 log_from_addr("nlm_nm_lock", rqstp);
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;
776 /* nlm_free_all ------------------------------------------------------------ */
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.
786 void *
787 /*ARGSUSED*/
788 nlm_free_all_3_svc(nlm_notify *arg, struct svc_req *rqstp)
790 static char dummy;
792 if (debug_level)
793 log_from_addr("nlm_free_all", rqstp);
794 return &dummy;
797 /* calls for nlm version 4 (NFSv3) */
798 /* nlm_test ---------------------------------------------------------------- */
800 * Purpose: Test whether a specified lock would be granted if requested
801 * Returns: nlm_granted (or error code)
802 * Notes:
804 nlm4_testres *
805 nlm4_test_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
807 static nlm4_testres result;
808 struct nlm4_holder *holder;
810 if (debug_level)
811 log_from_addr("nlm4_test", rqstp);
813 holder = testlock(&arg->alock, LOCK_V4);
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.
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));
830 return &result;
833 void *
834 nlm4_test_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
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;
844 if (debug_level)
845 log_from_addr("nlm4_test_msg", rqstp);
847 holder = testlock(&arg->alock, LOCK_V4);
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));
859 * nlm_test has different result type to the other operations, so
860 * can't use transmit4_result() in this case
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;
867 success = clnt_call(cli, NLM4_TEST_RES, xdr_nlm4_testres,
868 &result, xdr_void, &dummy, timeo);
870 if (debug_level > 2)
871 syslog(LOG_DEBUG, "clnt_call returns %d", success);
873 return NULL;
876 /* nlm_lock ---------------------------------------------------------------- */
878 * Purposes: Establish a lock
879 * Returns: granted, denied or blocked
880 * Notes: *** grace period support missing
882 nlm4_res *
883 nlm4_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
885 static nlm4_res result;
887 if (debug_level)
888 log_from_addr("nlm4_lock", rqstp);
890 /* copy cookie from arg to result. See comment in nlm_test_4() */
891 result.cookie = arg->cookie;
893 result.stat.stat = (enum nlm4_stats)getlock(arg, rqstp,
894 LOCK_MON | LOCK_V4);
895 return &result;
898 void *
899 nlm4_lock_msg_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
901 static nlm4_res result;
903 if (debug_level)
904 log_from_addr("nlm4_lock_msg", rqstp);
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));
912 return NULL;
915 /* nlm_cancel -------------------------------------------------------------- */
917 * Purpose: Cancel a blocked lock request
918 * Returns: granted or denied
919 * Notes:
921 nlm4_res *
922 nlm4_cancel_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
924 static nlm4_res result;
926 if (debug_level)
927 log_from_addr("nlm4_cancel", rqstp);
929 /* copy cookie from arg to result. See comment in nlm_test_1() */
930 result.cookie = arg->cookie;
933 * Since at present we never return 'nlm_blocked', there can never be
934 * a lock to cancel, so this call always fails.
936 result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_CANCEL);
937 return &result;
940 void *
941 nlm4_cancel_msg_4_svc(nlm4_cancargs *arg, struct svc_req *rqstp)
943 static nlm4_res result;
945 if (debug_level)
946 log_from_addr("nlm4_cancel_msg", rqstp);
948 result.cookie = arg->cookie;
950 * Since at present we never return 'nlm_blocked', there can never be
951 * a lock to cancel, so this call always fails.
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;
960 /* nlm_unlock -------------------------------------------------------------- */
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.
968 nlm4_res *
969 nlm4_unlock_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
971 static nlm4_res result;
973 if (debug_level)
974 log_from_addr("nlm4_unlock", rqstp);
976 result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_V4);
977 result.cookie = arg->cookie;
979 return &result;
982 void *
983 nlm4_unlock_msg_4_svc(nlm4_unlockargs *arg, struct svc_req *rqstp)
985 static nlm4_res result;
987 if (debug_level)
988 log_from_addr("nlm4_unlock_msg", rqstp);
990 result.stat.stat = (enum nlm4_stats)unlock(&arg->alock, LOCK_V4);
991 result.cookie = arg->cookie;
993 transmit4_result(NLM4_UNLOCK_RES, &result,
994 (struct sockaddr *)(void *)svc_getcaller(rqstp->rq_xprt));
995 return NULL;
998 /* ------------------------------------------------------------------------- */
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.
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.
1010 /* nlm_granted ------------------------------------------------------------- */
1012 * Purpose: Receive notification that formerly blocked lock now granted
1013 * Returns: always success ('granted')
1014 * Notes:
1016 nlm4_res *
1017 nlm4_granted_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
1019 static nlm4_res result;
1021 if (debug_level)
1022 log_from_addr("nlm4_granted", rqstp);
1024 /* copy cookie from arg to result. See comment in nlm_test_1() */
1025 result.cookie = arg->cookie;
1027 result.stat.stat = nlm4_granted;
1028 return &result;
1031 void *
1032 nlm4_granted_msg_4_svc(nlm4_testargs *arg, struct svc_req *rqstp)
1034 static nlm4_res result;
1036 if (debug_level)
1037 log_from_addr("nlm4_granted_msg", rqstp);
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;
1046 /* nlm_test_res ------------------------------------------------------------ */
1048 * Purpose: Accept result from earlier nlm_test_msg() call
1049 * Returns: Nothing
1051 void *
1052 /*ARGSUSED*/
1053 nlm4_test_res_4_svc(nlm4_testres *arg, struct svc_req *rqstp)
1055 if (debug_level)
1056 log_from_addr("nlm4_test_res", rqstp);
1057 return NULL;
1060 /* nlm_lock_res ------------------------------------------------------------ */
1062 * Purpose: Accept result from earlier nlm_lock_msg() call
1063 * Returns: Nothing
1065 void *
1066 /*ARGSUSED*/
1067 nlm4_lock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
1069 if (debug_level)
1070 log_from_addr("nlm4_lock_res", rqstp);
1072 return NULL;
1075 /* nlm_cancel_res ---------------------------------------------------------- */
1077 * Purpose: Accept result from earlier nlm_cancel_msg() call
1078 * Returns: Nothing
1080 void *
1081 /*ARGSUSED*/
1082 nlm4_cancel_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
1084 if (debug_level)
1085 log_from_addr("nlm4_cancel_res", rqstp);
1086 return NULL;
1089 /* nlm_unlock_res ---------------------------------------------------------- */
1091 * Purpose: Accept result from earlier nlm_unlock_msg() call
1092 * Returns: Nothing
1094 void *
1095 /*ARGSUSED*/
1096 nlm4_unlock_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
1098 if (debug_level)
1099 log_from_addr("nlm4_unlock_res", rqstp);
1100 return NULL;
1103 /* nlm_granted_res --------------------------------------------------------- */
1105 * Purpose: Accept result from earlier nlm_granted_msg() call
1106 * Returns: Nothing
1108 void *
1109 /*ARGSUSED*/
1110 nlm4_granted_res_4_svc(nlm4_res *arg, struct svc_req *rqstp)
1112 if (debug_level)
1113 log_from_addr("nlm4_granted_res", rqstp);
1114 return NULL;
1117 /* ------------------------------------------------------------------------- */
1119 * Calls for PCNFS locking (aka non-monitored locking, no involvement
1120 * of rpc.statd).
1122 * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
1125 /* nlm_share --------------------------------------------------------------- */
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.
1132 nlm4_shareres *
1133 nlm4_share_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
1135 static nlm4_shareres result;
1137 if (debug_level)
1138 log_from_addr("nlm4_share", rqstp);
1140 result.cookie = arg->cookie;
1141 result.stat = nlm4_granted;
1142 result.sequence = 1234356; /* X/Open says this field is ignored? */
1143 return &result;
1146 /* nlm4_unshare ------------------------------------------------------------ */
1148 * Purpose: Release a DOS-style lock
1149 * Returns: nlm_granted, unless in grace period
1150 * Notes:
1152 nlm4_shareres *
1153 nlm4_unshare_4_svc(nlm4_shareargs *arg, struct svc_req *rqstp)
1155 static nlm4_shareres result;
1157 if (debug_level)
1158 log_from_addr("nlm_unshare", rqstp);
1160 result.cookie = arg->cookie;
1161 result.stat = nlm4_granted;
1162 result.sequence = 1234356; /* X/Open says this field is ignored? */
1163 return &result;
1166 /* nlm4_nm_lock ------------------------------------------------------------ */
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.
1176 nlm4_res *
1177 nlm4_nm_lock_4_svc(nlm4_lockargs *arg, struct svc_req *rqstp)
1179 static nlm4_res result;
1181 if (debug_level)
1182 log_from_addr("nlm4_nm_lock", rqstp);
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;
1190 /* nlm4_free_all ------------------------------------------------------------ */
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.
1200 void *
1201 /*ARGSUSED*/
1202 nlm4_free_all_4_svc(nlm_notify *arg, struct svc_req *rqstp)
1204 static char dummy;
1206 if (debug_level)
1207 log_from_addr("nlm4_free_all", rqstp);
1208 return &dummy;
1211 /* nlm_sm_notify --------------------------------------------------------- */
1213 * Purpose: called by rpc.statd when a monitored host state changes.
1214 * Returns: Nothing
1216 void *
1217 /*ARGSUSED*/
1218 nlm_sm_notify_0_svc(struct nlm_sm_status *arg, struct svc_req *rqstp)
1220 static char dummy;
1221 notify(arg->mon_name, arg->state);
1222 return &dummy;