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