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