1 /* $NetBSD: lock_proc.c,v 1.8 2007/11/04 19:59:54 tron Exp $ */
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
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
36 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: lock_proc.c,v 1.8 2007/11/04 19:59:54 tron Exp $");
41 #include <sys/param.h>
42 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
51 #include <netconfig.h>
54 #include <rpcsvc/sm_inter.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
72 * Notes: Extracts the source address from the transport handle
73 * passed in as part of the called procedure specification
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)
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;
124 addrcmp(const struct sockaddr
*sa1
, const struct sockaddr
*sa2
)
129 if (sa1
->sa_family
!= sa2
->sa_family
)
132 switch (sa1
->sa_family
) {
134 p1
= &((const struct sockaddr_in
*)(const void *)sa1
)->sin_addr
;
135 p2
= &((const struct sockaddr_in
*)(const void *)sa2
)->sin_addr
;
139 p1
= &((const struct sockaddr_in6
*)(const void *)sa1
)->sin6_addr
;
140 p2
= &((const struct sockaddr_in6
*)(const void *)sa2
)->sin6_addr
;
147 return memcmp(p1
, p2
, len
);
151 get_client(struct sockaddr
*host_addr
, rpcvers_t vers
)
154 struct timeval retry_time
, time_now
;
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. */
172 syslog(LOG_DEBUG
, "Expired CLIENT* in cache");
173 clnt_cache_time
[i
] = 0L;
174 clnt_destroy(client
);
175 clnt_cache_ptr
[i
] = NULL
;
178 if (client
&& !addrcmp((const struct sockaddr
*)(const void *)
179 &clnt_cache_addr
[i
], host_addr
)) {
182 syslog(LOG_DEBUG
, "Found CLIENT* in cache");
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");
204 if (host_addr
->sa_family
== AF_INET6
)
209 if (host_addr
->sa_family
== AF_INET6
)
214 nconf
= getnetconfigent(netid
);
216 syslog(LOG_ERR
, "could not get netconfig info for '%s': "
217 "no /etc/netconfig file?", netid
);
221 client
= clnt_tp_create(host
, NLM_PROG
, vers
, nconf
);
222 freenetconfigent(nconf
);
225 syslog(LOG_ERR
, "%s", clnt_spcreateerror("clntudp_create"));
226 syslog(LOG_ERR
, "Unable to return result to %s", host
);
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
);
248 syslog(LOG_DEBUG
, "Created CLIENT* for %s", host
);
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
262 transmit_result(int opcode
, nlm_res
*result
, struct sockaddr
*addr
)
266 struct timeval timeo
;
269 if ((cli
= get_client(addr
, NLM_VERS
)) != NULL
) {
270 timeo
.tv_sec
= 0; /* No timeout - not expecting response */
273 success
= clnt_call(cli
, (rpcproc_t
)opcode
, xdr_nlm_res
,
274 result
, xdr_void
, &dummy
, timeo
);
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
290 transmit4_result(int opcode
, nlm4_res
*result
, struct sockaddr
*addr
)
294 struct timeval timeo
;
297 if ((cli
= get_client(addr
, NLM_VERS4
)) != NULL
) {
298 timeo
.tv_sec
= 0; /* No timeout - not expecting response */
301 success
= clnt_call(cli
, (rpcproc_t
)opcode
, xdr_nlm4_res
,
302 result
, xdr_void
, &dummy
, timeo
);
305 syslog(LOG_DEBUG
, "clnt_call returns %d(%s)",
306 success
, clnt_sperrno(success
));
311 * converts a struct nlm_lock to struct nlm4_lock
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"
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
348 /* nlm_test ---------------------------------------------------------------- */
350 * Purpose: Test whether a specified lock would be granted if requested
351 * Returns: nlm_granted (or error code)
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
);
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
;
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
;
389 nlm_test_msg_1_svc(nlm_testargs
*arg
, struct svc_req
*rqstp
)
393 struct sockaddr
*addr
;
396 struct timeval timeo
;
397 struct nlm4_lock arg4
;
398 struct nlm4_holder
*holder
;
400 nlmtonlm4(&arg
->alock
, &arg4
);
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
;
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 */
429 success
= clnt_call(cli
, NLM_TEST_RES
, xdr_nlm_testres
,
430 &result
, xdr_void
, &dummy
, timeo
);
433 syslog(LOG_DEBUG
, "clnt_call returns %d", success
);
438 /* nlm_lock ---------------------------------------------------------------- */
440 * Purposes: Establish a lock
441 * Returns: granted, denied or blocked
442 * Notes: *** grace period support missing
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
;
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
);
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
;
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
));
490 /* nlm_cancel -------------------------------------------------------------- */
492 * Purpose: Cancel a blocked lock request
493 * Returns: granted or denied
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
);
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
);
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
);
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
));
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.
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
);
557 log_from_addr("nlm_unlock", rqstp
);
559 result
.stat
.stat
= unlock(&arg4
, 0);
560 result
.cookie
= arg
->cookie
;
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
);
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
));
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
596 /* nlm_granted ------------------------------------------------------------- */
598 * Purpose: Receive notification that formerly blocked lock now granted
599 * Returns: always success ('granted')
603 nlm_granted_1_svc(nlm_testargs
*arg
, struct svc_req
*rqstp
)
605 static nlm_res result
;
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
;
618 nlm_granted_msg_1_svc(nlm_testargs
*arg
, struct svc_req
*rqstp
)
620 static nlm_res result
;
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
));
632 /* nlm_test_res ------------------------------------------------------------ */
634 * Purpose: Accept result from earlier nlm_test_msg() call
639 nlm_test_res_1_svc(nlm_testres
*arg
, struct svc_req
*rqstp
)
642 log_from_addr("nlm_test_res", rqstp
);
646 /* nlm_lock_res ------------------------------------------------------------ */
648 * Purpose: Accept result from earlier nlm_lock_msg() call
653 nlm_lock_res_1_svc(nlm_res
*arg
, struct svc_req
*rqstp
)
656 log_from_addr("nlm_lock_res", rqstp
);
661 /* nlm_cancel_res ---------------------------------------------------------- */
663 * Purpose: Accept result from earlier nlm_cancel_msg() call
668 nlm_cancel_res_1_svc(nlm_res
*arg
, struct svc_req
*rqstp
)
671 log_from_addr("nlm_cancel_res", rqstp
);
675 /* nlm_unlock_res ---------------------------------------------------------- */
677 * Purpose: Accept result from earlier nlm_unlock_msg() call
682 nlm_unlock_res_1_svc(nlm_res
*arg
, struct svc_req
*rqstp
)
685 log_from_addr("nlm_unlock_res", rqstp
);
689 /* nlm_granted_res --------------------------------------------------------- */
691 * Purpose: Accept result from earlier nlm_granted_msg() call
696 nlm_granted_res_1_svc(nlm_res
*arg
, struct svc_req
*rqstp
)
699 log_from_addr("nlm_granted_res", rqstp
);
703 /* ------------------------------------------------------------------------- */
705 * Calls for PCNFS locking (aka non-monitored locking, no involvement
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.
719 nlm_share_3_svc(nlm_shareargs
*arg
, struct svc_req
*rqstp
)
721 static nlm_shareres result
;
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? */
732 /* nlm_unshare ------------------------------------------------------------ */
734 * Purpose: Release a DOS-style lock
735 * Returns: nlm_granted, unless in grace period
739 nlm_unshare_3_svc(nlm_shareargs
*arg
, struct svc_req
*rqstp
)
741 static nlm_shareres result
;
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? */
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.
763 nlm_nm_lock_3_svc(nlm_lockargs
*arg
, struct svc_req
*rqstp
)
765 static nlm_res result
;
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
;
776 /* nlm_free_all ------------------------------------------------------------ */
778 * Purpose: Release all locks held by a named client
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.
788 nlm_free_all_3_svc(nlm_notify
*arg
, struct svc_req
*rqstp
)
793 log_from_addr("nlm_free_all", rqstp
);
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)
805 nlm4_test_4_svc(nlm4_testargs
*arg
, struct svc_req
*rqstp
)
807 static nlm4_testres result
;
808 struct nlm4_holder
*holder
;
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
;
826 result
.stat
.stat
= nlm4_denied
;
827 (void)memcpy(&result
.stat
.nlm4_testrply_u
.holder
, holder
,
828 sizeof(struct nlm4_holder
));
834 nlm4_test_msg_4_svc(nlm4_testargs
*arg
, struct svc_req
*rqstp
)
838 struct sockaddr
*addr
;
841 struct timeval timeo
;
842 struct nlm4_holder
*holder
;
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
;
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 */
867 success
= clnt_call(cli
, NLM4_TEST_RES
, xdr_nlm4_testres
,
868 &result
, xdr_void
, &dummy
, timeo
);
871 syslog(LOG_DEBUG
, "clnt_call returns %d", success
);
876 /* nlm_lock ---------------------------------------------------------------- */
878 * Purposes: Establish a lock
879 * Returns: granted, denied or blocked
880 * Notes: *** grace period support missing
883 nlm4_lock_4_svc(nlm4_lockargs
*arg
, struct svc_req
*rqstp
)
885 static nlm4_res result
;
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
,
899 nlm4_lock_msg_4_svc(nlm4_lockargs
*arg
, struct svc_req
*rqstp
)
901 static nlm4_res result
;
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
));
915 /* nlm_cancel -------------------------------------------------------------- */
917 * Purpose: Cancel a blocked lock request
918 * Returns: granted or denied
922 nlm4_cancel_4_svc(nlm4_cancargs
*arg
, struct svc_req
*rqstp
)
924 static nlm4_res result
;
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
);
941 nlm4_cancel_msg_4_svc(nlm4_cancargs
*arg
, struct svc_req
*rqstp
)
943 static nlm4_res result
;
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
));
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.
969 nlm4_unlock_4_svc(nlm4_unlockargs
*arg
, struct svc_req
*rqstp
)
971 static nlm4_res result
;
974 log_from_addr("nlm4_unlock", rqstp
);
976 result
.stat
.stat
= (enum nlm4_stats
)unlock(&arg
->alock
, LOCK_V4
);
977 result
.cookie
= arg
->cookie
;
983 nlm4_unlock_msg_4_svc(nlm4_unlockargs
*arg
, struct svc_req
*rqstp
)
985 static nlm4_res result
;
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
));
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
1010 /* nlm_granted ------------------------------------------------------------- */
1012 * Purpose: Receive notification that formerly blocked lock now granted
1013 * Returns: always success ('granted')
1017 nlm4_granted_4_svc(nlm4_testargs
*arg
, struct svc_req
*rqstp
)
1019 static nlm4_res result
;
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
;
1032 nlm4_granted_msg_4_svc(nlm4_testargs
*arg
, struct svc_req
*rqstp
)
1034 static nlm4_res result
;
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
);
1046 /* nlm_test_res ------------------------------------------------------------ */
1048 * Purpose: Accept result from earlier nlm_test_msg() call
1053 nlm4_test_res_4_svc(nlm4_testres
*arg
, struct svc_req
*rqstp
)
1056 log_from_addr("nlm4_test_res", rqstp
);
1060 /* nlm_lock_res ------------------------------------------------------------ */
1062 * Purpose: Accept result from earlier nlm_lock_msg() call
1067 nlm4_lock_res_4_svc(nlm4_res
*arg
, struct svc_req
*rqstp
)
1070 log_from_addr("nlm4_lock_res", rqstp
);
1075 /* nlm_cancel_res ---------------------------------------------------------- */
1077 * Purpose: Accept result from earlier nlm_cancel_msg() call
1082 nlm4_cancel_res_4_svc(nlm4_res
*arg
, struct svc_req
*rqstp
)
1085 log_from_addr("nlm4_cancel_res", rqstp
);
1089 /* nlm_unlock_res ---------------------------------------------------------- */
1091 * Purpose: Accept result from earlier nlm_unlock_msg() call
1096 nlm4_unlock_res_4_svc(nlm4_res
*arg
, struct svc_req
*rqstp
)
1099 log_from_addr("nlm4_unlock_res", rqstp
);
1103 /* nlm_granted_res --------------------------------------------------------- */
1105 * Purpose: Accept result from earlier nlm_granted_msg() call
1110 nlm4_granted_res_4_svc(nlm4_res
*arg
, struct svc_req
*rqstp
)
1113 log_from_addr("nlm4_granted_res", rqstp
);
1117 /* ------------------------------------------------------------------------- */
1119 * Calls for PCNFS locking (aka non-monitored locking, no involvement
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.
1133 nlm4_share_4_svc(nlm4_shareargs
*arg
, struct svc_req
*rqstp
)
1135 static nlm4_shareres result
;
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? */
1146 /* nlm4_unshare ------------------------------------------------------------ */
1148 * Purpose: Release a DOS-style lock
1149 * Returns: nlm_granted, unless in grace period
1153 nlm4_unshare_4_svc(nlm4_shareargs
*arg
, struct svc_req
*rqstp
)
1155 static nlm4_shareres result
;
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? */
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.
1177 nlm4_nm_lock_4_svc(nlm4_lockargs
*arg
, struct svc_req
*rqstp
)
1179 static nlm4_res result
;
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
;
1190 /* nlm4_free_all ------------------------------------------------------------ */
1192 * Purpose: Release all locks held by a named client
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.
1202 nlm4_free_all_4_svc(nlm_notify
*arg
, struct svc_req
*rqstp
)
1207 log_from_addr("nlm4_free_all", rqstp
);
1211 /* nlm_sm_notify --------------------------------------------------------- */
1213 * Purpose: called by rpc.statd when a monitored host state changes.
1218 nlm_sm_notify_0_svc(struct nlm_sm_status
*arg
, struct svc_req
*rqstp
)
1221 notify(arg
->mon_name
, arg
->state
);