lock_proc.c revision 1.1 1 1.1 scottr /* $NetBSD: lock_proc.c,v 1.1 1997/03/10 06:26:20 scottr Exp $ */
2 1.1 scottr
3 1.1 scottr /*
4 1.1 scottr * Copyright (c) 1995
5 1.1 scottr * A.R. Gordon (andrew.gordon (at) net-tel.co.uk). All rights reserved.
6 1.1 scottr *
7 1.1 scottr * Redistribution and use in source and binary forms, with or without
8 1.1 scottr * modification, are permitted provided that the following conditions
9 1.1 scottr * are met:
10 1.1 scottr * 1. Redistributions of source code must retain the above copyright
11 1.1 scottr * notice, this list of conditions and the following disclaimer.
12 1.1 scottr * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 scottr * notice, this list of conditions and the following disclaimer in the
14 1.1 scottr * documentation and/or other materials provided with the distribution.
15 1.1 scottr * 3. All advertising materials mentioning features or use of this software
16 1.1 scottr * must display the following acknowledgement:
17 1.1 scottr * This product includes software developed for the FreeBSD project
18 1.1 scottr * 4. Neither the name of the author nor the names of any co-contributors
19 1.1 scottr * may be used to endorse or promote products derived from this software
20 1.1 scottr * without specific prior written permission.
21 1.1 scottr *
22 1.1 scottr * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
23 1.1 scottr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.1 scottr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.1 scottr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 1.1 scottr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.1 scottr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.1 scottr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.1 scottr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.1 scottr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.1 scottr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.1 scottr * SUCH DAMAGE.
33 1.1 scottr *
34 1.1 scottr */
35 1.1 scottr
36 1.1 scottr #include <stdio.h>
37 1.1 scottr #include <netdb.h>
38 1.1 scottr #include <string.h>
39 1.1 scottr #include <syslog.h>
40 1.1 scottr #include <sys/param.h>
41 1.1 scottr #include <sys/socket.h>
42 1.1 scottr
43 1.1 scottr #include <netinet/in.h>
44 1.1 scottr #include <arpa/inet.h>
45 1.1 scottr
46 1.1 scottr #include <rpc/rpc.h>
47 1.1 scottr #include <rpcsvc/sm_inter.h>
48 1.1 scottr
49 1.1 scottr #include "lockd.h"
50 1.1 scottr #include "nlm_prot.h"
51 1.1 scottr
52 1.1 scottr
53 1.1 scottr #define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */
54 1.1 scottr #define CLIENT_CACHE_LIFETIME 120 /* In seconds */
55 1.1 scottr
56 1.1 scottr /* log_from_addr ----------------------------------------------------------- */
57 1.1 scottr /*
58 1.1 scottr * Purpose: Log name of function called and source address
59 1.1 scottr * Returns: Nothing
60 1.1 scottr * Notes: Extracts the source address from the transport handle
61 1.1 scottr * passed in as part of the called procedure specification
62 1.1 scottr */
63 1.1 scottr static void
64 1.1 scottr log_from_addr(fun_name, req)
65 1.1 scottr char *fun_name;
66 1.1 scottr struct svc_req *req;
67 1.1 scottr {
68 1.1 scottr struct sockaddr_in *addr;
69 1.1 scottr struct hostent *host;
70 1.1 scottr char hostname_buf[40];
71 1.1 scottr
72 1.1 scottr addr = svc_getcaller(req->rq_xprt);
73 1.1 scottr host = gethostbyaddr((char *)&(addr->sin_addr), addr->sin_len, AF_INET);
74 1.1 scottr if (host) {
75 1.1 scottr strncpy(hostname_buf, host->h_name, sizeof(hostname_buf));
76 1.1 scottr hostname_buf[sizeof(hostname_buf) - 1] = '\0';
77 1.1 scottr } else /* No hostname available - print raw address */
78 1.1 scottr strcpy(hostname_buf, inet_ntoa(addr->sin_addr));
79 1.1 scottr
80 1.1 scottr syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf);
81 1.1 scottr }
82 1.1 scottr
83 1.1 scottr /* get_client -------------------------------------------------------------- */
84 1.1 scottr /*
85 1.1 scottr * Purpose: Get a CLIENT* for making RPC calls to lockd on given host
86 1.1 scottr * Returns: CLIENT* pointer, from clnt_udp_create, or NULL if error
87 1.1 scottr * Notes: Creating a CLIENT* is quite expensive, involving a
88 1.1 scottr * conversation with the remote portmapper to get the
89 1.1 scottr * port number. Since a given client is quite likely
90 1.1 scottr * to make several locking requests in succession, it is
91 1.1 scottr * desirable to cache the created CLIENT*.
92 1.1 scottr *
93 1.1 scottr * Since we are using UDP rather than TCP, there is no cost
94 1.1 scottr * to the remote system in keeping these cached indefinitely.
95 1.1 scottr * Unfortunately there is a snag: if the remote system
96 1.1 scottr * reboots, the cached portmapper results will be invalid,
97 1.1 scottr * and we will never detect this since all of the xxx_msg()
98 1.1 scottr * calls return no result - we just fire off a udp packet
99 1.1 scottr * and hope for the best.
100 1.1 scottr *
101 1.1 scottr * We solve this by discarding cached values after two
102 1.1 scottr * minutes, regardless of whether they have been used
103 1.1 scottr * in the meanwhile (since a bad one might have been used
104 1.1 scottr * plenty of times, as the host keeps retrying the request
105 1.1 scottr * and we keep sending the reply back to the wrong port).
106 1.1 scottr *
107 1.1 scottr * Given that the entries will always expire in the order
108 1.1 scottr * that they were created, there is no point in a LRU
109 1.1 scottr * algorithm for when the cache gets full - entries are
110 1.1 scottr * always re-used in sequence.
111 1.1 scottr */
112 1.1 scottr static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE];
113 1.1 scottr static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */
114 1.1 scottr static struct in_addr clnt_cache_addr[CLIENT_CACHE_SIZE];
115 1.1 scottr static int clnt_cache_next_to_use = 0;
116 1.1 scottr
117 1.1 scottr static CLIENT *
118 1.1 scottr get_client(host_addr)
119 1.1 scottr struct sockaddr_in *host_addr;
120 1.1 scottr {
121 1.1 scottr CLIENT *client;
122 1.1 scottr struct timeval retry_time, time_now;
123 1.1 scottr int i, sock_no;
124 1.1 scottr
125 1.1 scottr gettimeofday(&time_now, NULL);
126 1.1 scottr
127 1.1 scottr /*
128 1.1 scottr * Search for the given client in the cache, zapping any expired
129 1.1 scottr * entries that we happen to notice in passing.
130 1.1 scottr */
131 1.1 scottr for (i = 0; i < CLIENT_CACHE_SIZE; i++) {
132 1.1 scottr client = clnt_cache_ptr[i];
133 1.1 scottr if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME)
134 1.1 scottr < time_now.tv_sec)) {
135 1.1 scottr /* Cache entry has expired. */
136 1.1 scottr if (debug_level > 3)
137 1.1 scottr syslog(LOG_DEBUG, "Expired CLIENT* in cache");
138 1.1 scottr clnt_cache_time[i] = 0L;
139 1.1 scottr clnt_destroy(client);
140 1.1 scottr clnt_cache_ptr[i] = NULL;
141 1.1 scottr client = NULL;
142 1.1 scottr }
143 1.1 scottr if (client && !memcmp(&clnt_cache_addr[i],
144 1.1 scottr &host_addr->sin_addr, sizeof(struct in_addr))) {
145 1.1 scottr /* Found it! */
146 1.1 scottr if (debug_level > 3)
147 1.1 scottr syslog(LOG_DEBUG, "Found CLIENT* in cache");
148 1.1 scottr return (client);
149 1.1 scottr }
150 1.1 scottr }
151 1.1 scottr
152 1.1 scottr /* Not found in cache. Free the next entry if it is in use. */
153 1.1 scottr if (clnt_cache_ptr[clnt_cache_next_to_use]) {
154 1.1 scottr clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]);
155 1.1 scottr clnt_cache_ptr[clnt_cache_next_to_use] = NULL;
156 1.1 scottr }
157 1.1 scottr
158 1.1 scottr /* Create the new client handle */
159 1.1 scottr sock_no = RPC_ANYSOCK;
160 1.1 scottr retry_time.tv_sec = 5;
161 1.1 scottr retry_time.tv_usec = 0;
162 1.1 scottr host_addr->sin_port = 0; /* Force consultation with portmapper */
163 1.1 scottr client = clntudp_create(host_addr, NLM_PROG, NLM_VERS,
164 1.1 scottr retry_time, &sock_no);
165 1.1 scottr if (!client) {
166 1.1 scottr syslog(LOG_ERR, clnt_spcreateerror("clntudp_create"));
167 1.1 scottr syslog(LOG_ERR, "Unable to return result to %s",
168 1.1 scottr inet_ntoa(host_addr->sin_addr));
169 1.1 scottr return NULL;
170 1.1 scottr }
171 1.1 scottr
172 1.1 scottr /* Success - update the cache entry */
173 1.1 scottr clnt_cache_ptr[clnt_cache_next_to_use] = client;
174 1.1 scottr clnt_cache_addr[clnt_cache_next_to_use] = host_addr->sin_addr;
175 1.1 scottr clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec;
176 1.1 scottr if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE)
177 1.1 scottr clnt_cache_next_to_use = 0;
178 1.1 scottr
179 1.1 scottr /*
180 1.1 scottr * Disable the default timeout, so we can specify our own in calls
181 1.1 scottr * to clnt_call(). (Note that the timeout is a different concept
182 1.1 scottr * from the retry period set in clnt_udp_create() above.)
183 1.1 scottr */
184 1.1 scottr retry_time.tv_sec = -1;
185 1.1 scottr retry_time.tv_usec = -1;
186 1.1 scottr clnt_control(client, CLSET_TIMEOUT, (char *)&retry_time);
187 1.1 scottr
188 1.1 scottr if (debug_level > 3)
189 1.1 scottr syslog(LOG_DEBUG, "Created CLIENT* for %s",
190 1.1 scottr inet_ntoa(host_addr->sin_addr));
191 1.1 scottr return client;
192 1.1 scottr }
193 1.1 scottr
194 1.1 scottr
195 1.1 scottr /* transmit_result --------------------------------------------------------- */
196 1.1 scottr /*
197 1.1 scottr * Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs
198 1.1 scottr * Returns: Nothing - we have no idea if the datagram got there
199 1.1 scottr * Notes: clnt_call() will always fail (with timeout) as we are
200 1.1 scottr * calling it with timeout 0 as a hack to just issue a datagram
201 1.1 scottr * without expecting a result
202 1.1 scottr */
203 1.1 scottr static void
204 1.1 scottr transmit_result(opcode, result, req)
205 1.1 scottr int opcode;
206 1.1 scottr nlm_res *result;
207 1.1 scottr struct svc_req *req;
208 1.1 scottr {
209 1.1 scottr static char dummy;
210 1.1 scottr struct sockaddr_in *addr;
211 1.1 scottr CLIENT *cli;
212 1.1 scottr struct timeval timeo;
213 1.1 scottr int success;
214 1.1 scottr
215 1.1 scottr addr = svc_getcaller(req->rq_xprt);
216 1.1 scottr if (cli = get_client(addr)) {
217 1.1 scottr timeo.tv_sec = 0; /* No timeout - not expecting response */
218 1.1 scottr timeo.tv_usec = 0;
219 1.1 scottr
220 1.1 scottr success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void,
221 1.1 scottr &dummy, timeo);
222 1.1 scottr
223 1.1 scottr if (debug_level > 2)
224 1.1 scottr syslog(LOG_DEBUG, "clnt_call returns %d\n", success);
225 1.1 scottr }
226 1.1 scottr }
227 1.1 scottr /* ------------------------------------------------------------------------- */
228 1.1 scottr /*
229 1.1 scottr * Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd
230 1.1 scottr * involved to ensure reclaim of locks after a crash of the "stateless"
231 1.1 scottr * server.
232 1.1 scottr *
233 1.1 scottr * These all come in two flavours - nlm_xxx() and nlm_xxx_msg().
234 1.1 scottr * The first are standard RPCs with argument and result.
235 1.1 scottr * The nlm_xxx_msg() calls implement exactly the same functions, but
236 1.1 scottr * use two pseudo-RPCs (one in each direction). These calls are NOT
237 1.1 scottr * standard use of the RPC protocol in that they do not return a result
238 1.1 scottr * at all (NB. this is quite different from returning a void result).
239 1.1 scottr * The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged
240 1.1 scottr * datagrams, requiring higher-level code to perform retries.
241 1.1 scottr *
242 1.1 scottr * Despite the disadvantages of the nlm_xxx_msg() approach (some of which
243 1.1 scottr * are documented in the comments to get_client() above), this is the
244 1.1 scottr * interface used by all current commercial NFS implementations
245 1.1 scottr * [Solaris, SCO, AIX etc.]. This is presumed to be because these allow
246 1.1 scottr * implementations to continue using the standard RPC libraries, while
247 1.1 scottr * avoiding the block-until-result nature of the library interface.
248 1.1 scottr *
249 1.1 scottr * No client implementations have been identified so far that make use
250 1.1 scottr * of the true RPC version (early SunOS releases would be a likely candidate
251 1.1 scottr * for testing).
252 1.1 scottr */
253 1.1 scottr
254 1.1 scottr /* nlm_test ---------------------------------------------------------------- */
255 1.1 scottr /*
256 1.1 scottr * Purpose: Test whether a specified lock would be granted if requested
257 1.1 scottr * Returns: nlm_granted (or error code)
258 1.1 scottr * Notes:
259 1.1 scottr */
260 1.1 scottr nlm_testres *
261 1.1 scottr nlm_test_1_svc(arg, rqstp)
262 1.1 scottr nlm_testargs *arg;
263 1.1 scottr struct svc_req *rqstp;
264 1.1 scottr {
265 1.1 scottr static nlm_testres res;
266 1.1 scottr
267 1.1 scottr if (debug_level)
268 1.1 scottr log_from_addr("nlm_test", rqstp);
269 1.1 scottr
270 1.1 scottr /*
271 1.1 scottr * Copy the cookie from the argument into the result. Note that this
272 1.1 scottr * is slightly hazardous, as the structure contains a pointer to a
273 1.1 scottr * malloc()ed buffer that will get freed by the caller. However, the
274 1.1 scottr * main function transmits the result before freeing the argument
275 1.1 scottr * so it is in fact safe.
276 1.1 scottr */
277 1.1 scottr res.cookie = arg->cookie;
278 1.1 scottr res.stat.stat = nlm_granted;
279 1.1 scottr return (&res);
280 1.1 scottr }
281 1.1 scottr
282 1.1 scottr void *
283 1.1 scottr nlm_test_msg_1_svc(arg, rqstp)
284 1.1 scottr nlm_testargs *arg;
285 1.1 scottr struct svc_req *rqstp;
286 1.1 scottr {
287 1.1 scottr nlm_testres res;
288 1.1 scottr static char dummy;
289 1.1 scottr struct sockaddr_in *addr;
290 1.1 scottr CLIENT *cli;
291 1.1 scottr int success;
292 1.1 scottr struct timeval timeo;
293 1.1 scottr
294 1.1 scottr if (debug_level)
295 1.1 scottr log_from_addr("nlm_test_msg", rqstp);
296 1.1 scottr
297 1.1 scottr res.cookie = arg->cookie;
298 1.1 scottr res.stat.stat = nlm_granted;
299 1.1 scottr
300 1.1 scottr /*
301 1.1 scottr * nlm_test has different result type to the other operations, so
302 1.1 scottr * can't use transmit_result() in this case
303 1.1 scottr */
304 1.1 scottr addr = svc_getcaller(rqstp->rq_xprt);
305 1.1 scottr if (cli = get_client(addr)) {
306 1.1 scottr timeo.tv_sec = 0; /* No timeout - not expecting response */
307 1.1 scottr timeo.tv_usec = 0;
308 1.1 scottr
309 1.1 scottr success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres,
310 1.1 scottr &res, xdr_void, &dummy, timeo);
311 1.1 scottr
312 1.1 scottr if (debug_level > 2)
313 1.1 scottr syslog(LOG_DEBUG, "clnt_call returns %d\n", success);
314 1.1 scottr }
315 1.1 scottr return (NULL);
316 1.1 scottr }
317 1.1 scottr
318 1.1 scottr /* nlm_lock ---------------------------------------------------------------- */
319 1.1 scottr /*
320 1.1 scottr * Purposes: Establish a lock
321 1.1 scottr * Returns: granted, denied or blocked
322 1.1 scottr * Notes: *** grace period support missing
323 1.1 scottr */
324 1.1 scottr nlm_res *
325 1.1 scottr nlm_lock_1_svc(arg, rqstp)
326 1.1 scottr nlm_lockargs *arg;
327 1.1 scottr struct svc_req *rqstp;
328 1.1 scottr {
329 1.1 scottr static nlm_res res;
330 1.1 scottr
331 1.1 scottr if (debug_level)
332 1.1 scottr log_from_addr("nlm_lock", rqstp);
333 1.1 scottr
334 1.1 scottr /* copy cookie from arg to result. See comment in nlm_test_1() */
335 1.1 scottr res.cookie = arg->cookie;
336 1.1 scottr
337 1.1 scottr res.stat.stat = nlm_granted;
338 1.1 scottr return (&res);
339 1.1 scottr }
340 1.1 scottr
341 1.1 scottr void *
342 1.1 scottr nlm_lock_msg_1_svc(arg, rqstp)
343 1.1 scottr nlm_lockargs *arg;
344 1.1 scottr struct svc_req *rqstp;
345 1.1 scottr {
346 1.1 scottr static nlm_res res;
347 1.1 scottr
348 1.1 scottr if (debug_level)
349 1.1 scottr log_from_addr("nlm_lock_msg", rqstp);
350 1.1 scottr
351 1.1 scottr res.cookie = arg->cookie;
352 1.1 scottr res.stat.stat = nlm_granted;
353 1.1 scottr transmit_result(NLM_LOCK_RES, &res, rqstp);
354 1.1 scottr
355 1.1 scottr return (NULL);
356 1.1 scottr }
357 1.1 scottr
358 1.1 scottr /* nlm_cancel -------------------------------------------------------------- */
359 1.1 scottr /*
360 1.1 scottr * Purpose: Cancel a blocked lock request
361 1.1 scottr * Returns: granted or denied
362 1.1 scottr * Notes:
363 1.1 scottr */
364 1.1 scottr nlm_res *
365 1.1 scottr nlm_cancel_1_svc(arg, rqstp)
366 1.1 scottr nlm_cancargs *arg;
367 1.1 scottr struct svc_req *rqstp;
368 1.1 scottr {
369 1.1 scottr static nlm_res res;
370 1.1 scottr
371 1.1 scottr if (debug_level)
372 1.1 scottr log_from_addr("nlm_cancel", rqstp);
373 1.1 scottr
374 1.1 scottr /* copy cookie from arg to result. See comment in nlm_test_1() */
375 1.1 scottr res.cookie = arg->cookie;
376 1.1 scottr
377 1.1 scottr /*
378 1.1 scottr * Since at present we never return 'nlm_blocked', there can never be
379 1.1 scottr * a lock to cancel, so this call always fails.
380 1.1 scottr */
381 1.1 scottr res.stat.stat = nlm_denied;
382 1.1 scottr return (&res);
383 1.1 scottr }
384 1.1 scottr
385 1.1 scottr void *
386 1.1 scottr nlm_cancel_msg_1_svc(arg, rqstp)
387 1.1 scottr nlm_cancargs *arg;
388 1.1 scottr struct svc_req *rqstp;
389 1.1 scottr {
390 1.1 scottr static nlm_res res;
391 1.1 scottr
392 1.1 scottr if (debug_level)
393 1.1 scottr log_from_addr("nlm_cancel_msg", rqstp);
394 1.1 scottr
395 1.1 scottr res.cookie = arg->cookie;
396 1.1 scottr /*
397 1.1 scottr * Since at present we never return 'nlm_blocked', there can never be
398 1.1 scottr * a lock to cancel, so this call always fails.
399 1.1 scottr */
400 1.1 scottr res.stat.stat = nlm_denied;
401 1.1 scottr transmit_result(NLM_CANCEL_RES, &res, rqstp);
402 1.1 scottr return (NULL);
403 1.1 scottr }
404 1.1 scottr
405 1.1 scottr /* nlm_unlock -------------------------------------------------------------- */
406 1.1 scottr /*
407 1.1 scottr * Purpose: Release an existing lock
408 1.1 scottr * Returns: Always granted, unless during grace period
409 1.1 scottr * Notes: "no such lock" error condition is ignored, as the
410 1.1 scottr * protocol uses unreliable UDP datagrams, and may well
411 1.1 scottr * re-try an unlock that has already succeeded.
412 1.1 scottr */
413 1.1 scottr nlm_res *
414 1.1 scottr nlm_unlock_1_svc(arg, rqstp)
415 1.1 scottr nlm_unlockargs *arg;
416 1.1 scottr struct svc_req *rqstp;
417 1.1 scottr {
418 1.1 scottr static nlm_res res;
419 1.1 scottr
420 1.1 scottr if (debug_level)
421 1.1 scottr log_from_addr("nlm_unlock", rqstp);
422 1.1 scottr
423 1.1 scottr res.stat.stat = nlm_granted;
424 1.1 scottr res.cookie = arg->cookie;
425 1.1 scottr
426 1.1 scottr return (&res);
427 1.1 scottr }
428 1.1 scottr
429 1.1 scottr void *
430 1.1 scottr nlm_unlock_msg_1_svc(arg, rqstp)
431 1.1 scottr nlm_unlockargs *arg;
432 1.1 scottr struct svc_req *rqstp;
433 1.1 scottr {
434 1.1 scottr static nlm_res res;
435 1.1 scottr
436 1.1 scottr if (debug_level)
437 1.1 scottr log_from_addr("nlm_unlock_msg", rqstp);
438 1.1 scottr
439 1.1 scottr res.stat.stat = nlm_granted;
440 1.1 scottr res.cookie = arg->cookie;
441 1.1 scottr
442 1.1 scottr transmit_result(NLM_UNLOCK_RES, &res, rqstp);
443 1.1 scottr return (NULL);
444 1.1 scottr }
445 1.1 scottr
446 1.1 scottr /* ------------------------------------------------------------------------- */
447 1.1 scottr /*
448 1.1 scottr * Client-side pseudo-RPCs for results. Note that for the client there
449 1.1 scottr * are only nlm_xxx_msg() versions of each call, since the 'real RPC'
450 1.1 scottr * version returns the results in the RPC result, and so the client
451 1.1 scottr * does not normally receive incoming RPCs.
452 1.1 scottr *
453 1.1 scottr * The exception to this is nlm_granted(), which is genuinely an RPC
454 1.1 scottr * call from the server to the client - a 'call-back' in normal procedure
455 1.1 scottr * call terms.
456 1.1 scottr */
457 1.1 scottr
458 1.1 scottr /* nlm_granted ------------------------------------------------------------- */
459 1.1 scottr /*
460 1.1 scottr * Purpose: Receive notification that formerly blocked lock now granted
461 1.1 scottr * Returns: always success ('granted')
462 1.1 scottr * Notes:
463 1.1 scottr */
464 1.1 scottr nlm_res *
465 1.1 scottr nlm_granted_1_svc(arg, rqstp)
466 1.1 scottr nlm_testargs *arg;
467 1.1 scottr struct svc_req *rqstp;
468 1.1 scottr {
469 1.1 scottr static nlm_res res;
470 1.1 scottr
471 1.1 scottr if (debug_level)
472 1.1 scottr log_from_addr("nlm_granted", rqstp);
473 1.1 scottr
474 1.1 scottr /* copy cookie from arg to result. See comment in nlm_test_1() */
475 1.1 scottr res.cookie = arg->cookie;
476 1.1 scottr
477 1.1 scottr res.stat.stat = nlm_granted;
478 1.1 scottr return (&res);
479 1.1 scottr }
480 1.1 scottr
481 1.1 scottr void *
482 1.1 scottr nlm_granted_msg_1_svc(arg, rqstp)
483 1.1 scottr nlm_testargs *arg;
484 1.1 scottr struct svc_req *rqstp;
485 1.1 scottr {
486 1.1 scottr static nlm_res res;
487 1.1 scottr
488 1.1 scottr if (debug_level)
489 1.1 scottr log_from_addr("nlm_granted_msg", rqstp);
490 1.1 scottr
491 1.1 scottr res.cookie = arg->cookie;
492 1.1 scottr res.stat.stat = nlm_granted;
493 1.1 scottr transmit_result(NLM_GRANTED_RES, &res, rqstp);
494 1.1 scottr return (NULL);
495 1.1 scottr }
496 1.1 scottr
497 1.1 scottr /* nlm_test_res ------------------------------------------------------------ */
498 1.1 scottr /*
499 1.1 scottr * Purpose: Accept result from earlier nlm_test_msg() call
500 1.1 scottr * Returns: Nothing
501 1.1 scottr */
502 1.1 scottr void *
503 1.1 scottr nlm_test_res_1_svc(arg, rqstp)
504 1.1 scottr nlm_testres *arg;
505 1.1 scottr struct svc_req *rqstp;
506 1.1 scottr {
507 1.1 scottr if (debug_level)
508 1.1 scottr log_from_addr("nlm_test_res", rqstp);
509 1.1 scottr return (NULL);
510 1.1 scottr }
511 1.1 scottr
512 1.1 scottr /* nlm_lock_res ------------------------------------------------------------ */
513 1.1 scottr /*
514 1.1 scottr * Purpose: Accept result from earlier nlm_lock_msg() call
515 1.1 scottr * Returns: Nothing
516 1.1 scottr */
517 1.1 scottr void *
518 1.1 scottr nlm_lock_res_1_svc(arg, rqstp)
519 1.1 scottr nlm_res *arg;
520 1.1 scottr struct svc_req *rqstp;
521 1.1 scottr {
522 1.1 scottr if (debug_level)
523 1.1 scottr log_from_addr("nlm_lock_res", rqstp);
524 1.1 scottr
525 1.1 scottr return (NULL);
526 1.1 scottr }
527 1.1 scottr
528 1.1 scottr /* nlm_cancel_res ---------------------------------------------------------- */
529 1.1 scottr /*
530 1.1 scottr * Purpose: Accept result from earlier nlm_cancel_msg() call
531 1.1 scottr * Returns: Nothing
532 1.1 scottr */
533 1.1 scottr void *
534 1.1 scottr nlm_cancel_res_1_svc(arg, rqstp)
535 1.1 scottr nlm_res *arg;
536 1.1 scottr struct svc_req *rqstp;
537 1.1 scottr {
538 1.1 scottr if (debug_level)
539 1.1 scottr log_from_addr("nlm_cancel_res", rqstp);
540 1.1 scottr return (NULL);
541 1.1 scottr }
542 1.1 scottr
543 1.1 scottr /* nlm_unlock_res ---------------------------------------------------------- */
544 1.1 scottr /*
545 1.1 scottr * Purpose: Accept result from earlier nlm_unlock_msg() call
546 1.1 scottr * Returns: Nothing
547 1.1 scottr */
548 1.1 scottr void *
549 1.1 scottr nlm_unlock_res_1_svc(arg, rqstp)
550 1.1 scottr nlm_res *arg;
551 1.1 scottr struct svc_req *rqstp;
552 1.1 scottr {
553 1.1 scottr if (debug_level)
554 1.1 scottr log_from_addr("nlm_unlock_res", rqstp);
555 1.1 scottr return (NULL);
556 1.1 scottr }
557 1.1 scottr
558 1.1 scottr /* nlm_granted_res --------------------------------------------------------- */
559 1.1 scottr /*
560 1.1 scottr * Purpose: Accept result from earlier nlm_granted_msg() call
561 1.1 scottr * Returns: Nothing
562 1.1 scottr */
563 1.1 scottr void *
564 1.1 scottr nlm_granted_res_1_svc(arg, rqstp)
565 1.1 scottr nlm_res *arg;
566 1.1 scottr struct svc_req *rqstp;
567 1.1 scottr {
568 1.1 scottr if (debug_level)
569 1.1 scottr log_from_addr("nlm_granted_res", rqstp);
570 1.1 scottr return (NULL);
571 1.1 scottr }
572 1.1 scottr
573 1.1 scottr /* ------------------------------------------------------------------------- */
574 1.1 scottr /*
575 1.1 scottr * Calls for PCNFS locking (aka non-monitored locking, no involvement
576 1.1 scottr * of rpc.statd).
577 1.1 scottr *
578 1.1 scottr * These are all genuine RPCs - no nlm_xxx_msg() nonsense here.
579 1.1 scottr */
580 1.1 scottr
581 1.1 scottr /* nlm_share --------------------------------------------------------------- */
582 1.1 scottr /*
583 1.1 scottr * Purpose: Establish a DOS-style lock
584 1.1 scottr * Returns: success or failure
585 1.1 scottr * Notes: Blocking locks are not supported - client is expected
586 1.1 scottr * to retry if required.
587 1.1 scottr */
588 1.1 scottr nlm_shareres *
589 1.1 scottr nlm_share_3_svc(arg, rqstp)
590 1.1 scottr nlm_shareargs *arg;
591 1.1 scottr struct svc_req *rqstp;
592 1.1 scottr {
593 1.1 scottr static nlm_shareres res;
594 1.1 scottr
595 1.1 scottr if (debug_level)
596 1.1 scottr log_from_addr("nlm_share", rqstp);
597 1.1 scottr
598 1.1 scottr res.cookie = arg->cookie;
599 1.1 scottr res.stat = nlm_granted;
600 1.1 scottr res.sequence = 1234356; /* X/Open says this field is ignored? */
601 1.1 scottr return (&res);
602 1.1 scottr }
603 1.1 scottr
604 1.1 scottr /* nlm_unshare ------------------------------------------------------------ */
605 1.1 scottr /*
606 1.1 scottr * Purpose: Release a DOS-style lock
607 1.1 scottr * Returns: nlm_granted, unless in grace period
608 1.1 scottr * Notes:
609 1.1 scottr */
610 1.1 scottr nlm_shareres *
611 1.1 scottr nlm_unshare_3_svc(arg, rqstp)
612 1.1 scottr nlm_shareargs *arg;
613 1.1 scottr struct svc_req *rqstp;
614 1.1 scottr {
615 1.1 scottr static nlm_shareres res;
616 1.1 scottr
617 1.1 scottr if (debug_level)
618 1.1 scottr log_from_addr("nlm_unshare", rqstp);
619 1.1 scottr
620 1.1 scottr res.cookie = arg->cookie;
621 1.1 scottr res.stat = nlm_granted;
622 1.1 scottr res.sequence = 1234356; /* X/Open says this field is ignored? */
623 1.1 scottr return (&res);
624 1.1 scottr }
625 1.1 scottr
626 1.1 scottr /* nlm_nm_lock ------------------------------------------------------------ */
627 1.1 scottr /*
628 1.1 scottr * Purpose: non-monitored version of nlm_lock()
629 1.1 scottr * Returns: as for nlm_lock()
630 1.1 scottr * Notes: These locks are in the same style as the standard nlm_lock,
631 1.1 scottr * but the rpc.statd should not be called to establish a
632 1.1 scottr * monitor for the client machine, since that machine is
633 1.1 scottr * declared not to be running a rpc.statd, and so would not
634 1.1 scottr * respond to the statd protocol.
635 1.1 scottr */
636 1.1 scottr nlm_res *
637 1.1 scottr nlm_nm_lock_3_svc(arg, rqstp)
638 1.1 scottr nlm_lockargs *arg;
639 1.1 scottr struct svc_req *rqstp;
640 1.1 scottr {
641 1.1 scottr static nlm_res res;
642 1.1 scottr
643 1.1 scottr if (debug_level)
644 1.1 scottr log_from_addr("nlm_nm_lock", rqstp);
645 1.1 scottr
646 1.1 scottr /* copy cookie from arg to result. See comment in nlm_test_1() */
647 1.1 scottr res.cookie = arg->cookie;
648 1.1 scottr res.stat.stat = nlm_granted;
649 1.1 scottr return (&res);
650 1.1 scottr }
651 1.1 scottr
652 1.1 scottr /* nlm_free_all ------------------------------------------------------------ */
653 1.1 scottr /*
654 1.1 scottr * Purpose: Release all locks held by a named client
655 1.1 scottr * Returns: Nothing
656 1.1 scottr * Notes: Potential denial of service security problem here - the
657 1.1 scottr * locks to be released are specified by a host name, independent
658 1.1 scottr * of the address from which the request has arrived.
659 1.1 scottr * Should probably be rejected if the named host has been
660 1.1 scottr * using monitored locks.
661 1.1 scottr */
662 1.1 scottr void *
663 1.1 scottr nlm_free_all_3_svc(arg, rqstp)
664 1.1 scottr nlm_notify *arg;
665 1.1 scottr struct svc_req *rqstp;
666 1.1 scottr {
667 1.1 scottr static char dummy;
668 1.1 scottr
669 1.1 scottr if (debug_level)
670 1.1 scottr log_from_addr("nlm_free_all", rqstp);
671 1.1 scottr return (&dummy);
672 1.1 scottr }
673