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