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