kern.c revision 86188
1/*-
2 * Copyright (c) 1997 Berkeley Software Design, Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. Berkeley Software Design Inc's name may not be used to endorse or
13 *    promote products derived from this software without specific prior
14 *    written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 *      from BSDI kern.c,v 1.2 1998/11/25 22:38:27 don Exp
29 * $FreeBSD: head/usr.sbin/rpc.lockd/kern.c 86188 2001-11-08 10:37:32Z alfred $
30 */
31
32#include <sys/param.h>
33#include <sys/mount.h>
34#include <sys/queue.h>
35#include <sys/socket.h>
36#include <sys/stat.h>
37
38#include <err.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <syslog.h>
45#include <unistd.h>
46
47#include "nlm_prot.h"
48#include <nfs/rpcv2.h>
49#include <nfs/nfsproto.h>
50#include <nfsclient/nfs_lock.h>
51
52#include "lockd.h"
53#include "lockd_lock.h"
54#include <nfsclient/nfs.h>
55
56#define nfslockdans(_v, _ansp)	\
57	((_ansp)->la_vers = _v, \
58	nfsclnt(NFSCLNT_LOCKDANS, _ansp))
59
60/* Lock request owner. */
61typedef struct __owner {
62	pid_t	 pid;				/* Process ID. */
63	time_t	 tod;				/* Time-of-day. */
64} OWNER;
65static OWNER owner;
66
67static char hostname[MAXHOSTNAMELEN + 1];	/* Hostname. */
68
69int	lock_request(LOCKD_MSG *);
70int	test_request(LOCKD_MSG *);
71void	show(LOCKD_MSG *);
72int	unlock_request(LOCKD_MSG *);
73
74/*
75 * will break because fifo needs to be repopened when EOF'd
76 */
77#ifdef SETUID_DAEMON
78#define lockd_seteuid(uid)	seteuid(uid)
79#else
80#define lockd_seteuid(uid)	(1)
81#endif
82
83#define d_calls (debug_level > 1)
84#define d_args (debug_level > 2)
85
86#define from_addr(sockaddr) \
87	(inet_ntoa((sockaddr)->sin_addr))
88
89void
90client_cleanup(sig, code)
91	int sig;
92	int code;
93{
94	(void)lockd_seteuid(0);
95	(void)unlink(_PATH_LCKFIFO);
96	exit(-1);
97}
98
99/*
100 * client_request --
101 *	Loop around messages from the kernel, forwarding them off to
102 *	NLM servers.
103 */
104pid_t
105client_request(void)
106{
107	LOCKD_MSG msg;
108	fd_set rdset;
109	int fd, nr, ret;
110	pid_t child;
111
112	/* Recreate the NLM fifo. */
113	(void)unlink(_PATH_LCKFIFO);
114	(void)umask(S_IXGRP|S_IXOTH);
115	if (mkfifo(_PATH_LCKFIFO, S_IWUSR | S_IRUSR)) {
116		syslog(LOG_ERR, "mkfifo: %s: %m", _PATH_LCKFIFO);
117		exit (1);
118	}
119
120	/*
121	 * Create a separate process, the client code is really a separate
122	 * daemon that shares a lot of code.
123	 */
124	switch (child = fork()) {
125	case -1:
126		err(1, "fork");
127	case 0:
128		break;
129	default:
130		return (child);
131	}
132
133	signal(SIGHUP, client_cleanup);
134	signal(SIGTERM, client_cleanup);
135
136	/* Setup. */
137	(void)time(&owner.tod);
138	owner.pid = getpid();
139	(void)gethostname(hostname, sizeof(hostname) - 1);
140
141	/* Open the fifo for reading. */
142	if ((fd = open(_PATH_LCKFIFO, O_RDONLY | O_NONBLOCK)) < 0)
143		syslog(LOG_ERR, "open: %s: %m", _PATH_LCKFIFO);
144
145	/* drop our root priviledges */
146	(void)lockd_seteuid(daemon_uid);
147
148	for (;;) {
149		/* Wait for contact... fifo's return EAGAIN when read with
150		 * no data
151		 */
152		/* Set up the select. */
153		FD_ZERO(&rdset);
154		FD_SET(fd, &rdset);
155		(void)select(fd + 1, &rdset, NULL, NULL, NULL);
156
157		/* Read the fixed length message. */
158		if ((nr = read(fd, &msg, sizeof(msg))) == sizeof(msg)) {
159			if (d_args)
160				show(&msg);
161
162			if (msg.lm_version != LOCKD_MSG_VERSION) {
163				syslog(LOG_ERR,
164				    "unknown msg type: %d", msg.lm_version);
165			}
166			/*
167			 * Send it to the NLM server and don't grant the lock
168			 * if we fail for any reason.
169			 */
170			switch (msg.lm_fl.l_type) {
171			case F_RDLCK:
172			case F_WRLCK:
173				if (msg.lm_getlk)
174					ret = test_request(&msg);
175				else
176					ret = lock_request(&msg);
177				break;
178			case F_UNLCK:
179				ret = unlock_request(&msg);
180				break;
181			default:
182				ret = 1;
183				syslog(LOG_ERR,
184				    "unknown lock type: %d", msg.lm_fl.l_type);
185				break;
186			}
187			if (ret) {
188				struct lockd_ans ans;
189
190				ans.la_msg_ident = msg.lm_msg_ident;
191				ans.la_errno = EHOSTUNREACH;
192
193				if (nfslockdans(LOCKD_ANS_VERSION, &ans)) {
194					syslog((errno == EPIPE ? LOG_INFO :
195						LOG_ERR), "process %lu: %m",
196						(u_long)msg.lm_msg_ident.pid);
197				}
198			}
199		} else if (nr == -1) {
200			if (errno != EAGAIN) {
201				syslog(LOG_ERR, "read: %s: %m", _PATH_LCKFIFO);
202				goto err;
203			}
204		} else if (nr != 0) {
205			syslog(LOG_ERR,
206			    "%s: discard %d bytes", _PATH_LCKFIFO, nr);
207		}
208	}
209
210	/* Reached only on error. */
211err:
212	(void)lockd_seteuid(0);
213	(void)unlink(_PATH_LCKFIFO);
214	_exit (1);
215}
216
217void
218set_auth(cl, ucred)
219	CLIENT *cl;
220	struct ucred *ucred;
221{
222        if (cl->cl_auth != NULL)
223                cl->cl_auth->ah_ops->ah_destroy(cl->cl_auth);
224        cl->cl_auth = authunix_create(hostname,
225                        ucred->cr_uid,
226                        ucred->cr_groups[0],
227                        ucred->cr_ngroups-1,
228                        &ucred->cr_groups[1]);
229}
230
231
232/*
233 * test_request --
234 *	Convert a lock LOCKD_MSG into an NLM request, and send it off.
235 */
236int
237test_request(LOCKD_MSG *msg)
238{
239	CLIENT *cli;
240	struct timeval timeout = {0, 0};	/* No timeout, no response. */
241	char dummy;
242
243	if (d_calls)
244		syslog(LOG_DEBUG, "test request: %s: %s to %s",
245		    msg->lm_nfsv3 ? "V4" : "V1/3",
246		    msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
247		    from_addr((struct sockaddr_in *)&msg->lm_addr));
248
249	if (msg->lm_nfsv3) {
250		struct nlm4_testargs arg4;
251
252		arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident;
253		arg4.cookie.n_len = sizeof(msg->lm_msg_ident);
254		arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
255		arg4.alock.caller_name = hostname;
256		arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
257		arg4.alock.fh.n_len = msg->lm_fh_len;
258		arg4.alock.oh.n_bytes = (char *)&owner;
259		arg4.alock.oh.n_len = sizeof(owner);
260		arg4.alock.svid = msg->lm_msg_ident.pid;
261		arg4.alock.l_offset = msg->lm_fl.l_start;
262		arg4.alock.l_len = msg->lm_fl.l_len;
263
264		if ((cli = get_client(
265		    (struct sockaddr *)&msg->lm_addr,
266		    NLM_VERS4)) == NULL)
267			return (1);
268
269		set_auth(cli, &msg->lm_cred);
270		(void)clnt_call(cli, NLM_TEST_MSG,
271		    xdr_nlm4_testargs, &arg4, xdr_void, &dummy, timeout);
272	} else {
273		struct nlm_testargs arg;
274
275		arg.cookie.n_bytes = (char *)&msg->lm_msg_ident;
276		arg.cookie.n_len = sizeof(msg->lm_msg_ident);
277		arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
278		arg.alock.caller_name = hostname;
279		arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
280		arg.alock.fh.n_len = msg->lm_fh_len;
281		arg.alock.oh.n_bytes = (char *)&owner;
282		arg.alock.oh.n_len = sizeof(owner);
283		arg.alock.svid = msg->lm_msg_ident.pid;
284		arg.alock.l_offset = msg->lm_fl.l_start;
285		arg.alock.l_len = msg->lm_fl.l_len;
286
287		if ((cli = get_client(
288		    (struct sockaddr *)&msg->lm_addr,
289		    NLM_VERS)) == NULL)
290			return (1);
291
292		set_auth(cli, &msg->lm_cred);
293		(void)clnt_call(cli, NLM_TEST_MSG,
294		    xdr_nlm_testargs, &arg, xdr_void, &dummy, timeout);
295	}
296	return (0);
297}
298
299/*
300 * lock_request --
301 *	Convert a lock LOCKD_MSG into an NLM request, and send it off.
302 */
303int
304lock_request(LOCKD_MSG *msg)
305{
306	CLIENT *cli;
307	struct nlm4_lockargs arg4;
308	struct nlm_lockargs arg;
309	struct timeval timeout = {0, 0};	/* No timeout, no response. */
310	char dummy;
311
312	if (d_calls)
313		syslog(LOG_DEBUG, "lock request: %s: %s to %s",
314		    msg->lm_nfsv3 ? "V4" : "V1/3",
315		    msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
316		    from_addr((struct sockaddr_in *)&msg->lm_addr));
317
318	if (msg->lm_nfsv3) {
319		arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident;
320		arg4.cookie.n_len = sizeof(msg->lm_msg_ident);
321		arg4.block = msg->lm_wait ? 1 : 0;
322		arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
323		arg4.alock.caller_name = hostname;
324		arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
325		arg4.alock.fh.n_len = msg->lm_fh_len;
326		arg4.alock.oh.n_bytes = (char *)&owner;
327		arg4.alock.oh.n_len = sizeof(owner);
328		arg4.alock.svid = msg->lm_msg_ident.pid;
329		arg4.alock.l_offset = msg->lm_fl.l_start;
330		arg4.alock.l_len = msg->lm_fl.l_len;
331		arg4.reclaim = 0;
332		arg4.state = nsm_state;
333
334		if ((cli = get_client(
335		    (struct sockaddr *)&msg->lm_addr,
336		    NLM_VERS4)) == NULL)
337			return (1);
338
339		set_auth(cli, &msg->lm_cred);
340		(void)clnt_call(cli, NLM_LOCK_MSG,
341		    xdr_nlm4_lockargs, &arg4, xdr_void, &dummy, timeout);
342	} else {
343		arg.cookie.n_bytes = (char *)&msg->lm_msg_ident;
344		arg.cookie.n_len = sizeof(msg->lm_msg_ident);
345		arg.block = msg->lm_wait ? 1 : 0;
346		arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
347		arg.alock.caller_name = hostname;
348		arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
349		arg.alock.fh.n_len = msg->lm_fh_len;
350		arg.alock.oh.n_bytes = (char *)&owner;
351		arg.alock.oh.n_len = sizeof(owner);
352		arg.alock.svid = msg->lm_msg_ident.pid;
353		arg.alock.l_offset = msg->lm_fl.l_start;
354		arg.alock.l_len = msg->lm_fl.l_len;
355		arg.reclaim = 0;
356		arg.state = nsm_state;
357
358		if ((cli = get_client(
359		    (struct sockaddr *)&msg->lm_addr,
360		    NLM_VERS)) == NULL)
361			return (1);
362
363		set_auth(cli, &msg->lm_cred);
364		(void)clnt_call(cli, NLM_LOCK_MSG,
365		    xdr_nlm_lockargs, &arg, xdr_void, &dummy, timeout);
366	}
367	return (0);
368}
369
370/*
371 * unlock_request --
372 *	Convert an unlock LOCKD_MSG into an NLM request, and send it off.
373 */
374int
375unlock_request(LOCKD_MSG *msg)
376{
377	CLIENT *cli;
378	struct nlm4_unlockargs arg4;
379	struct nlm_unlockargs arg;
380	struct timeval timeout = {0, 0};	/* No timeout, no response. */
381	char dummy;
382
383	if (d_calls)
384		syslog(LOG_DEBUG, "unlock request: %s: to %s",
385		    msg->lm_nfsv3 ? "V4" : "V1/3",
386		    from_addr((struct sockaddr_in *)&msg->lm_addr));
387
388	if (msg->lm_nfsv3) {
389		arg4.cookie.n_bytes = (char *)&msg->lm_msg_ident;
390		arg4.cookie.n_len = sizeof(msg->lm_msg_ident);
391		arg4.alock.caller_name = hostname;
392		arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
393		arg4.alock.fh.n_len = msg->lm_fh_len;
394		arg4.alock.oh.n_bytes = (char *)&owner;
395		arg4.alock.oh.n_len = sizeof(owner);
396		arg4.alock.svid = msg->lm_msg_ident.pid;
397		arg4.alock.l_offset = msg->lm_fl.l_start;
398		arg4.alock.l_len = msg->lm_fl.l_len;
399
400		if ((cli = get_client(
401		    (struct sockaddr *)&msg->lm_addr,
402		    NLM_VERS4)) == NULL)
403			return (1);
404
405		set_auth(cli, &msg->lm_cred);
406		(void)clnt_call(cli, NLM_UNLOCK_MSG,
407		    xdr_nlm4_unlockargs, &arg4, xdr_void, &dummy, timeout);
408	} else {
409		arg.cookie.n_bytes = (char *)&msg->lm_msg_ident;
410		arg.cookie.n_len = sizeof(msg->lm_msg_ident);
411		arg.alock.caller_name = hostname;
412		arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
413		arg.alock.fh.n_len = msg->lm_fh_len;
414		arg.alock.oh.n_bytes = (char *)&owner;
415		arg.alock.oh.n_len = sizeof(owner);
416		arg.alock.svid = msg->lm_msg_ident.pid;
417		arg.alock.l_offset = msg->lm_fl.l_start;
418		arg.alock.l_len = msg->lm_fl.l_len;
419
420		if ((cli = get_client(
421		    (struct sockaddr *)&msg->lm_addr,
422		    NLM_VERS)) == NULL)
423			return (1);
424
425		set_auth(cli, &msg->lm_cred);
426		(void)clnt_call(cli, NLM_UNLOCK_MSG,
427		    xdr_nlm_unlockargs, &arg, xdr_void, &dummy, timeout);
428	}
429
430	return (0);
431}
432
433int
434lock_answer(int pid, netobj *netcookie, int result, int *pid_p, int version)
435{
436	struct lockd_ans ans;
437
438	if (netcookie->n_len != sizeof(ans.la_msg_ident)) {
439		if (pid == -1) {	/* we're screwed */
440			syslog(LOG_ERR, "inedible nlm cookie");
441			return -1;
442		}
443		ans.la_msg_ident.pid = pid;
444		ans.la_msg_ident.msg_seq = -1;
445	} else {
446		memcpy(&ans.la_msg_ident, netcookie->n_bytes,
447		    sizeof(ans.la_msg_ident));
448	}
449
450	if (d_calls)
451		syslog(LOG_DEBUG, "lock answer: pid %lu: %s %d",
452		    ans.la_msg_ident.pid,
453		    version == NLM_VERS4 ? "nlmv4" : "nlmv3",
454		    result);
455
456	ans.la_set_getlk_pid = 0;
457	if (version == NLM_VERS4)
458		switch (result) {
459		case nlm4_granted:
460			ans.la_errno = 0;
461			break;
462		default:
463			ans.la_errno = EACCES;
464			break;
465		case nlm4_denied:
466			if (pid_p == NULL)
467				ans.la_errno = EACCES;
468			else {
469				/* this is an answer to a nlm_test msg */
470				ans.la_set_getlk_pid = 1;
471				ans.la_getlk_pid = *pid_p;
472				ans.la_errno = 0;
473			}
474			break;
475		case nlm4_denied_nolocks:
476			ans.la_errno = EAGAIN;
477			break;
478		case nlm4_blocked:
479			return -1;
480			/* NOTREACHED */
481		case nlm4_denied_grace_period:
482			ans.la_errno = EAGAIN;
483			break;
484		case nlm4_deadlck:
485			ans.la_errno = EDEADLK;
486			break;
487		case nlm4_rofs:
488			ans.la_errno = EROFS;
489			break;
490		case nlm4_stale_fh:
491			ans.la_errno = ESTALE;
492			break;
493		case nlm4_fbig:
494			ans.la_errno = EFBIG;
495			break;
496		case nlm4_failed:
497			ans.la_errno = EACCES;
498			break;
499		}
500	else
501		switch (result) {
502		case nlm_granted:
503			ans.la_errno = 0;
504			break;
505		default:
506			ans.la_errno = EACCES;
507			break;
508		case nlm_denied:
509			if (pid_p == NULL)
510				ans.la_errno = EACCES;
511			else {
512				/* this is an answer to a nlm_test msg */
513				ans.la_set_getlk_pid = 1;
514				ans.la_getlk_pid = *pid_p;
515				ans.la_errno = 0;
516			}
517			break;
518		case nlm_denied_nolocks:
519			ans.la_errno = EAGAIN;
520			break;
521		case nlm_blocked:
522			return -1;
523			/* NOTREACHED */
524		case nlm_denied_grace_period:
525			ans.la_errno = EAGAIN;
526			break;
527		case nlm_deadlck:
528			ans.la_errno = EDEADLK;
529			break;
530		}
531
532	if (nfslockdans(LOCKD_ANS_VERSION, &ans)) {
533		syslog(((errno == EPIPE || errno == ESRCH) ?
534			LOG_INFO : LOG_ERR),
535			"process %lu: %m", (u_long)ans.la_msg_ident.pid);
536		return -1;
537	}
538	return 0;
539}
540
541/*
542 * show --
543 *	Display the contents of a kernel LOCKD_MSG structure.
544 */
545void
546show(LOCKD_MSG *mp)
547{
548	static char hex[] = "0123456789abcdef";
549	struct fid *fidp;
550	fsid_t *fsidp;
551	size_t len;
552	u_int8_t *p, *t, buf[NFS_SMALLFH*3+1];
553
554	syslog(LOG_DEBUG, "process ID: %lu\n", (long)mp->lm_msg_ident.pid);
555
556	fsidp = (fsid_t *)&mp->lm_fh;
557	fidp = (struct fid *)((u_int8_t *)&mp->lm_fh + sizeof(fsid_t));
558
559	for (t = buf, p = (u_int8_t *)mp->lm_fh,
560	    len = mp->lm_fh_len;
561	    len > 0; ++p, --len) {
562		*t++ = '\\';
563		*t++ = hex[(*p & 0xf0) >> 4];
564		*t++ = hex[*p & 0x0f];
565	}
566	*t = '\0';
567
568	syslog(LOG_DEBUG, "fh_len %d, fh %s\n", mp->lm_fh_len, buf);
569
570	/* Show flock structure. */
571	syslog(LOG_DEBUG, "start %qu; len %qu; pid %lu; type %d; whence %d\n",
572	    mp->lm_fl.l_start, mp->lm_fl.l_len, (u_long)mp->lm_fl.l_pid,
573	    mp->lm_fl.l_type, mp->lm_fl.l_whence);
574
575	/* Show wait flag. */
576	syslog(LOG_DEBUG, "wait was %s\n", mp->lm_wait ? "set" : "not set");
577}
578