1 /*
2  * linux/fs/lockd/svc4proc.c
3  *
4  * Lockd server procedures. We don't implement the NLM_*_RES
5  * procedures because we don't use the async procedures.
6  *
7  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
8  */
9 
10 #include <linux/types.h>
11 #include <linux/sched.h>
12 #include <linux/slab.h>
13 #include <linux/in.h>
14 #include <linux/sunrpc/svc.h>
15 #include <linux/sunrpc/clnt.h>
16 #include <linux/nfsd/nfsd.h>
17 #include <linux/lockd/lockd.h>
18 #include <linux/lockd/share.h>
19 #include <linux/lockd/sm_inter.h>
20 
21 
22 #define NLMDBG_FACILITY		NLMDBG_CLIENT
23 
24 static u32	nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
25 static void	nlm4svc_callback_exit(struct rpc_task *);
26 
27 /*
28  * Obtain client and file from arguments
29  */
30 static u32
nlm4svc_retrieve_args(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_host ** hostp,struct nlm_file ** filp)31 nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
32 			struct nlm_host **hostp, struct nlm_file **filp)
33 {
34 	struct nlm_host		*host = NULL;
35 	struct nlm_file		*file = NULL;
36 	struct nlm_lock		*lock = &argp->lock;
37 	u32			error = 0;
38 
39 	/* nfsd callbacks must have been installed for this procedure */
40 	if (!nlmsvc_ops)
41 		return nlm_lck_denied_nolocks;
42 
43 	/* Obtain handle for client host */
44 	if (rqstp->rq_client == NULL) {
45 		printk(KERN_NOTICE
46 			"lockd: unauthenticated request from (%08x:%d)\n",
47 			ntohl(rqstp->rq_addr.sin_addr.s_addr),
48 			ntohs(rqstp->rq_addr.sin_port));
49 		return nlm_lck_denied_nolocks;
50 	}
51 
52 	/* Obtain host handle */
53 	if (!(host = nlmsvc_lookup_host(rqstp))
54 	 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
55 		goto no_locks;
56 	*hostp = host;
57 
58 	/* Obtain file pointer. Not used by FREE_ALL call. */
59 	if (filp != NULL) {
60 		if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
61 			goto no_locks;
62 		*filp = file;
63 
64 		/* Set up the missing parts of the file_lock structure */
65 		lock->fl.fl_file  = &file->f_file;
66 		lock->fl.fl_owner = (fl_owner_t) host;
67 	}
68 
69 	return 0;
70 
71 no_locks:
72 	if (host)
73 		nlm_release_host(host);
74  	if (error)
75 		return error;
76 	return nlm_lck_denied_nolocks;
77 }
78 
79 /*
80  * NULL: Test for presence of service
81  */
82 static int
nlm4svc_proc_null(struct svc_rqst * rqstp,void * argp,void * resp)83 nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
84 {
85 	dprintk("lockd: NULL          called\n");
86 	return rpc_success;
87 }
88 
89 /*
90  * TEST: Check for conflicting lock
91  */
92 static int
nlm4svc_proc_test(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)93 nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
94 				         struct nlm_res  *resp)
95 {
96 	struct nlm_host	*host;
97 	struct nlm_file	*file;
98 
99 	dprintk("lockd: TEST4        called\n");
100 	resp->cookie = argp->cookie;
101 
102 	/* Don't accept test requests during grace period */
103 	if (nlmsvc_grace_period) {
104 		resp->status = nlm_lck_denied_grace_period;
105 		return rpc_success;
106 	}
107 
108 	/* Obtain client and file */
109 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
110 		return rpc_success;
111 
112 	/* Now check for conflicting locks */
113 	resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
114 
115 	dprintk("lockd: TEST4          status %d\n", ntohl(resp->status));
116 	nlm_release_host(host);
117 	nlm_release_file(file);
118 	return rpc_success;
119 }
120 
121 static int
nlm4svc_proc_lock(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)122 nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
123 				         struct nlm_res  *resp)
124 {
125 	struct nlm_host	*host;
126 	struct nlm_file	*file;
127 
128 	dprintk("lockd: LOCK          called\n");
129 
130 	resp->cookie = argp->cookie;
131 
132 	/* Don't accept new lock requests during grace period */
133 	if (nlmsvc_grace_period && !argp->reclaim) {
134 		resp->status = nlm_lck_denied_grace_period;
135 		return rpc_success;
136 	}
137 
138 	/* Obtain client and file */
139 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
140 		return rpc_success;
141 
142 #if 0
143 	/* If supplied state doesn't match current state, we assume it's
144 	 * an old request that time-warped somehow. Any error return would
145 	 * do in this case because it's irrelevant anyway.
146 	 *
147 	 * NB: We don't retrieve the remote host's state yet.
148 	 */
149 	if (host->h_nsmstate && host->h_nsmstate != argp->state) {
150 		resp->status = nlm_lck_denied_nolocks;
151 	} else
152 #endif
153 
154 	/* Now try to lock the file */
155 	resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
156 					argp->block, &argp->cookie);
157 
158 	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
159 	nlm_release_host(host);
160 	nlm_release_file(file);
161 	return rpc_success;
162 }
163 
164 static int
nlm4svc_proc_cancel(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)165 nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
166 				           struct nlm_res  *resp)
167 {
168 	struct nlm_host	*host;
169 	struct nlm_file	*file;
170 
171 	dprintk("lockd: CANCEL        called\n");
172 
173 	resp->cookie = argp->cookie;
174 
175 	/* Don't accept requests during grace period */
176 	if (nlmsvc_grace_period) {
177 		resp->status = nlm_lck_denied_grace_period;
178 		return rpc_success;
179 	}
180 
181 	/* Obtain client and file */
182 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
183 		return rpc_success;
184 
185 	/* Try to cancel request. */
186 	resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
187 
188 	dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
189 	nlm_release_host(host);
190 	nlm_release_file(file);
191 	return rpc_success;
192 }
193 
194 /*
195  * UNLOCK: release a lock
196  */
197 static int
nlm4svc_proc_unlock(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)198 nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
199 				           struct nlm_res  *resp)
200 {
201 	struct nlm_host	*host;
202 	struct nlm_file	*file;
203 
204 	dprintk("lockd: UNLOCK        called\n");
205 
206 	resp->cookie = argp->cookie;
207 
208 	/* Don't accept new lock requests during grace period */
209 	if (nlmsvc_grace_period) {
210 		resp->status = nlm_lck_denied_grace_period;
211 		return rpc_success;
212 	}
213 
214 	/* Obtain client and file */
215 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
216 		return rpc_success;
217 
218 	/* Now try to remove the lock */
219 	resp->status = nlmsvc_unlock(file, &argp->lock);
220 
221 	dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
222 	nlm_release_host(host);
223 	nlm_release_file(file);
224 	return rpc_success;
225 }
226 
227 /*
228  * GRANTED: A server calls us to tell that a process' lock request
229  * was granted
230  */
231 static int
nlm4svc_proc_granted(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)232 nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
233 				            struct nlm_res  *resp)
234 {
235 	resp->cookie = argp->cookie;
236 
237 	dprintk("lockd: GRANTED       called\n");
238 	resp->status = nlmclnt_grant(&argp->lock);
239 	dprintk("lockd: GRANTED       status %d\n", ntohl(resp->status));
240 	return rpc_success;
241 }
242 
243 /*
244  * `Async' versions of the above service routines. They aren't really,
245  * because we send the callback before the reply proper. I hope this
246  * doesn't break any clients.
247  */
248 static int
nlm4svc_proc_test_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)249 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
250 					     void	     *resp)
251 {
252 	struct nlm_res	res;
253 	u32		stat;
254 
255 	dprintk("lockd: TEST_MSG      called\n");
256 
257 	memset(&res, 0, sizeof(res));
258 
259 	if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0)
260 		stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res);
261 	return stat;
262 }
263 
264 static int
nlm4svc_proc_lock_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)265 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
266 					     void	     *resp)
267 {
268 	struct nlm_res	res;
269 	u32		stat;
270 
271 	dprintk("lockd: LOCK_MSG      called\n");
272 
273 	if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
274 		stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
275 	return stat;
276 }
277 
278 static int
nlm4svc_proc_cancel_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)279 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
280 					       void	       *resp)
281 {
282 	struct nlm_res	res;
283 	u32		stat;
284 
285 	dprintk("lockd: CANCEL_MSG    called\n");
286 
287 	if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
288 		stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
289 	return stat;
290 }
291 
292 static int
nlm4svc_proc_unlock_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)293 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
294                                                void            *resp)
295 {
296 	struct nlm_res	res;
297 	u32		stat;
298 
299 	dprintk("lockd: UNLOCK_MSG    called\n");
300 
301 	if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
302 		stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
303 	return stat;
304 }
305 
306 static int
nlm4svc_proc_granted_msg(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)307 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
308                                                 void            *resp)
309 {
310 	struct nlm_res	res;
311 	u32		stat;
312 
313 	dprintk("lockd: GRANTED_MSG   called\n");
314 
315 	if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
316 		stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
317 	return stat;
318 }
319 
320 /*
321  * SHARE: create a DOS share or alter existing share.
322  */
323 static int
nlm4svc_proc_share(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)324 nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
325 				          struct nlm_res  *resp)
326 {
327 	struct nlm_host	*host;
328 	struct nlm_file	*file;
329 
330 	dprintk("lockd: SHARE         called\n");
331 
332 	resp->cookie = argp->cookie;
333 
334 	/* Don't accept new lock requests during grace period */
335 	if (nlmsvc_grace_period && !argp->reclaim) {
336 		resp->status = nlm_lck_denied_grace_period;
337 		return rpc_success;
338 	}
339 
340 	/* Obtain client and file */
341 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
342 		return rpc_success;
343 
344 	/* Now try to create the share */
345 	resp->status = nlmsvc_share_file(host, file, argp);
346 
347 	dprintk("lockd: SHARE         status %d\n", ntohl(resp->status));
348 	nlm_release_host(host);
349 	nlm_release_file(file);
350 	return rpc_success;
351 }
352 
353 /*
354  * UNSHARE: Release a DOS share.
355  */
356 static int
nlm4svc_proc_unshare(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)357 nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
358 				            struct nlm_res  *resp)
359 {
360 	struct nlm_host	*host;
361 	struct nlm_file	*file;
362 
363 	dprintk("lockd: UNSHARE       called\n");
364 
365 	resp->cookie = argp->cookie;
366 
367 	/* Don't accept requests during grace period */
368 	if (nlmsvc_grace_period) {
369 		resp->status = nlm_lck_denied_grace_period;
370 		return rpc_success;
371 	}
372 
373 	/* Obtain client and file */
374 	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
375 		return rpc_success;
376 
377 	/* Now try to lock the file */
378 	resp->status = nlmsvc_unshare_file(host, file, argp);
379 
380 	dprintk("lockd: UNSHARE       status %d\n", ntohl(resp->status));
381 	nlm_release_host(host);
382 	nlm_release_file(file);
383 	return rpc_success;
384 }
385 
386 /*
387  * NM_LOCK: Create an unmonitored lock
388  */
389 static int
nlm4svc_proc_nm_lock(struct svc_rqst * rqstp,struct nlm_args * argp,struct nlm_res * resp)390 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
391 				            struct nlm_res  *resp)
392 {
393 	dprintk("lockd: NM_LOCK       called\n");
394 
395 	argp->monitor = 0;		/* just clean the monitor flag */
396 	return nlm4svc_proc_lock(rqstp, argp, resp);
397 }
398 
399 /*
400  * FREE_ALL: Release all locks and shares held by client
401  */
402 static int
nlm4svc_proc_free_all(struct svc_rqst * rqstp,struct nlm_args * argp,void * resp)403 nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
404 					     void            *resp)
405 {
406 	struct nlm_host	*host;
407 
408 	/* Obtain client */
409 	if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
410 		return rpc_success;
411 
412 	nlmsvc_free_host_resources(host);
413 	nlm_release_host(host);
414 	return rpc_success;
415 }
416 
417 /*
418  * SM_NOTIFY: private callback from statd (not part of official NLM proto)
419  */
420 static int
nlm4svc_proc_sm_notify(struct svc_rqst * rqstp,struct nlm_reboot * argp,void * resp)421 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
422 					      void	        *resp)
423 {
424 	struct sockaddr_in	saddr = rqstp->rq_addr;
425 	int			vers = rqstp->rq_vers;
426 	int			prot = rqstp->rq_prot;
427 	struct nlm_host		*host;
428 
429 	dprintk("lockd: SM_NOTIFY     called\n");
430 	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
431 	 || ntohs(saddr.sin_port) >= 1024) {
432 		printk(KERN_WARNING
433 			"lockd: rejected NSM callback from %08x:%d\n",
434 			ntohl(rqstp->rq_addr.sin_addr.s_addr),
435 			ntohs(rqstp->rq_addr.sin_port));
436 		return rpc_system_err;
437 	}
438 
439 	/* Obtain the host pointer for this NFS server and try to
440 	 * reclaim all locks we hold on this server.
441 	 */
442 	saddr.sin_addr.s_addr = argp->addr;
443 	if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
444 		nlmclnt_recovery(host, argp->state);
445 		nlm_release_host(host);
446 	}
447 
448 	/* If we run on an NFS server, delete all locks held by the client */
449 	if (nlmsvc_ops != NULL) {
450 		struct svc_client	*clnt;
451 		saddr.sin_addr.s_addr = argp->addr;
452 		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL
453 		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
454 			nlmsvc_free_host_resources(host);
455 		}
456 		nlm_release_host(host);
457 	}
458 
459 	return rpc_success;
460 }
461 
462 /*
463  * client sent a GRANTED_RES, let's remove the associated block
464  */
465 static int
nlm4svc_proc_granted_res(struct svc_rqst * rqstp,struct nlm_res * argp,void * resp)466 nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res  *argp,
467                                                 void            *resp)
468 {
469         if (!nlmsvc_ops)
470                 return rpc_success;
471 
472         dprintk("lockd: GRANTED_RES   called\n");
473 
474         nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
475         return rpc_success;
476 }
477 
478 
479 
480 /*
481  * This is the generic lockd callback for async RPC calls
482  */
483 static u32
nlm4svc_callback(struct svc_rqst * rqstp,u32 proc,struct nlm_res * resp)484 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
485 {
486 	struct nlm_host	*host;
487 	struct nlm_rqst	*call;
488 
489 	if (!(call = nlmclnt_alloc_call()))
490 		return rpc_system_err;
491 
492 	host = nlmclnt_lookup_host(&rqstp->rq_addr,
493 				rqstp->rq_prot, rqstp->rq_vers);
494 	if (!host) {
495 		kfree(call);
496 		return rpc_system_err;
497 	}
498 
499 	call->a_flags = RPC_TASK_ASYNC;
500 	call->a_host  = host;
501 	memcpy(&call->a_args, resp, sizeof(*resp));
502 
503 	if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0)
504 		goto error;
505 
506 	return rpc_success;
507  error:
508 	kfree(call);
509 	nlm_release_host(host);
510 	return rpc_system_err;
511 }
512 
513 static void
nlm4svc_callback_exit(struct rpc_task * task)514 nlm4svc_callback_exit(struct rpc_task *task)
515 {
516 	struct nlm_rqst	*call = (struct nlm_rqst *) task->tk_calldata;
517 
518 	if (task->tk_status < 0) {
519 		dprintk("lockd: %4d callback failed (errno = %d)\n",
520 					task->tk_pid, -task->tk_status);
521 	}
522 	nlm_release_host(call->a_host);
523 	kfree(call);
524 }
525 
526 /*
527  * NLM Server procedures.
528  */
529 
530 #define nlm4svc_encode_norep	nlm4svc_encode_void
531 #define nlm4svc_decode_norep	nlm4svc_decode_void
532 #define nlm4svc_decode_testres	nlm4svc_decode_void
533 #define nlm4svc_decode_lockres	nlm4svc_decode_void
534 #define nlm4svc_decode_unlockres	nlm4svc_decode_void
535 #define nlm4svc_decode_cancelres	nlm4svc_decode_void
536 #define nlm4svc_decode_grantedres	nlm4svc_decode_void
537 
538 #define nlm4svc_proc_none	nlm4svc_proc_null
539 #define nlm4svc_proc_test_res	nlm4svc_proc_null
540 #define nlm4svc_proc_lock_res	nlm4svc_proc_null
541 #define nlm4svc_proc_cancel_res	nlm4svc_proc_null
542 #define nlm4svc_proc_unlock_res	nlm4svc_proc_null
543 
544 struct nlm_void			{ int dummy; };
545 
546 #define PROC(name, xargt, xrest, argt, rest, respsize)	\
547  { (svc_procfunc) nlm4svc_proc_##name,	\
548    (kxdrproc_t) nlm4svc_decode_##xargt,	\
549    (kxdrproc_t) nlm4svc_encode_##xrest,	\
550    NULL,				\
551    sizeof(struct nlm_##argt),		\
552    sizeof(struct nlm_##rest),		\
553    0,					\
554    0,					\
555    respsize,				\
556  }
557 #define	Ck	(1+8)	/* cookie */
558 #define	No	(1+1024/4)	/* netobj */
559 #define	St	1	/* status */
560 #define	Rg	4	/* range (offset + length) */
561 struct svc_procedure		nlmsvc_procedures4[] = {
562   PROC(null,		void,		void,		void,	void, 1),
563   PROC(test,		testargs,	testres,	args,	res, Ck+St+2+No+Rg),
564   PROC(lock,		lockargs,	res,		args,	res, Ck+St),
565   PROC(cancel,		cancargs,	res,		args,	res, Ck+St),
566   PROC(unlock,		unlockargs,	res,		args,	res, Ck+St),
567   PROC(granted,		testargs,	res,		args,	res, Ck+St),
568   PROC(test_msg,	testargs,	norep,		args,	void, 1),
569   PROC(lock_msg,	lockargs,	norep,		args,	void, 1),
570   PROC(cancel_msg,	cancargs,	norep,		args,	void, 1),
571   PROC(unlock_msg,	unlockargs,	norep,		args,	void, 1),
572   PROC(granted_msg,	testargs,	norep,		args,	void, 1),
573   PROC(test_res,	testres,	norep,		res,	void, 1),
574   PROC(lock_res,	lockres,	norep,		res,	void, 1),
575   PROC(cancel_res,	cancelres,	norep,		res,	void, 1),
576   PROC(unlock_res,	unlockres,	norep,		res,	void, 1),
577   PROC(granted_res,	res,		norep,		res,	void, 1),
578   /* statd callback */
579   PROC(sm_notify,	reboot,		void,		reboot,	void, 1),
580   PROC(none,		void,		void,		void,	void, 0),
581   PROC(none,		void,		void,		void,	void, 0),
582   PROC(none,		void,		void,		void,	void, 0),
583   PROC(share,		shareargs,	shareres,	args,	res, Ck+St+1),
584   PROC(unshare,		shareargs,	shareres,	args,	res, Ck+St+1),
585   PROC(nm_lock,		lockargs,	res,		args,	res, Ck+St),
586   PROC(free_all,	notify,		void,		args,	void, 1),
587 
588 };
589