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