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