1/*
2 * Copyright (c) 2002-2010 Apple Inc.  All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*	$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $	*/
24/*	$FreeBSD: src/usr.sbin/rpc.lockd/lockd.c,v 1.13 2002/04/11 07:19:30 alfred Exp $ */
25
26/*
27 * Copyright (c) 1995
28 *	A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 *    notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in the
37 *    documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 *    must display the following acknowledgement:
40 *	This product includes software developed for the FreeBSD project
41 * 4. Neither the name of the author nor the names of any co-contributors
42 *    may be used to endorse or promote products derived from this software
43 *    without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 */
58
59#include <sys/cdefs.h>
60#ifndef lint
61__RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $");
62#endif
63
64/*
65 * main() function for NFS lock daemon.  Most of the code in this
66 * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x.
67 *
68 * The actual program logic is in the file lock_proc.c
69 */
70
71/* make sure we can handle lots of file descriptors */
72#include <sys/syslimits.h>
73#define _DARWIN_UNLIMITED_SELECT
74
75#include <sys/types.h>
76#include <sys/socket.h>
77
78#include <err.h>
79#include <stdio.h>
80#include <stdlib.h>
81#include <errno.h>
82#include <syslog.h>
83#include <signal.h>
84#include <string.h>
85#include <ctype.h>
86#include <unistd.h>
87#include <fcntl.h>
88#include <sys/stat.h>
89#include <sys/resource.h>
90#include <sys/sysctl.h>
91#include <sys/select.h>
92#include <libutil.h>
93#include <util.h>
94#include <launch.h>
95
96#include <oncrpc/rpc.h>
97#include <oncrpc/rpcb.h>
98
99#include "sm_inter.h"
100
101#include "lockd.h"
102#include "nlm_prot.h"
103int bindresvport_sa(int sd, struct sockaddr *sa);
104
105int		_rpcsvcdirty = 0;
106
107struct pidfh *pfh = NULL;
108
109const struct nfs_conf_lockd config_defaults =
110{
111	45,		/* grace_period */
112	60,		/* host_monitor_cache_timeout */
113	0,		/* port */
114	0,		/* send_using_tcp */
115	0,		/* send_using_mnt_transport */
116	180,		/* shutdown_delay_client */
117	180,		/* shutdown_delay_server */
118	1,		/* tcp */
119	1,		/* udp */
120	0,		/* verbose */
121};
122struct nfs_conf_lockd config;
123
124int lockudpsock, locktcpsock;
125int lockudp6sock, locktcp6sock;
126int udpport, tcpport;
127int udp6port, tcp6port;
128int grace_expired;
129int nsm_state;
130pid_t server_pid = -1;
131struct mon mon_host;
132time_t currsec;
133
134void	init_nsm(void);
135void	nlm_prog_0(struct svc_req *, SVCXPRT *);
136void	nlm_prog_1(struct svc_req *, SVCXPRT *);
137void	nlm_prog_3(struct svc_req *, SVCXPRT *);
138void	nlm_prog_4(struct svc_req *, SVCXPRT *);
139void	usage(void);
140
141static int config_read(struct nfs_conf_lockd *);
142static void sigalarm_grace_period_handler(void);
143static void handle_sigchld(int sig);
144void my_svc_run(void);
145
146static int statd_is_loaded(void);
147static int statd_load(void);
148static int statd_service_start(void);
149
150
151/*
152 * This is the start up of lockd. Lockd has two functions one is to receive
153 * request from the kernel and forward them to the appropriate servers, i.e.,
154 * the client side. The other is to handle request from the remote clients, i.e.,
155 * the server side. Note the client request use asynchronous rpc (_MSG procedures),
156 * so the server side will get the reply and then use an nfs system call to return
157 * the result to the kernel. We use two processes, one for the client and one for
158 * the server. This is due to the fact that rpc library is mt hostile. At a later
159 * date we should fix that. The client forks off the server since we're started by
160 * lockd and the client gets its receive right from lockd. When nfsd starts up it
161 * will send a "ping" request on a host port, launchd will then start lockd.
162 *
163 * This daemon is to be started by launchd, as such it follows the following
164 * launchd rules:
165 *	We don't:
166 *		call daemon(3)
167 *		call fork and having the parent process exit
168 *		change uids or gids.
169 *		set up the current working directory or chroot.
170 *		set the session id
171 * 		change stdio to /dev/null.
172 *		call setrusage(2)
173 *		call setpriority(2)
174 *		Ignore SIGTERM.
175 *	We are launched on demand
176 *		and we catch SIGTERM to exit cleanly.
177 *
178 * In practice daemonizing in the classic unix sense would probably be ok
179 * since we get invoke by traffic on a task_special_port, but we will play
180 * by the rules, its even easier to boot.
181 */
182
183int
184main(argc, argv)
185	int argc;
186	char **argv;
187{
188	SVCXPRT *transp;
189	struct sockaddr_storage saddr;
190	struct sockaddr_in *sin = (struct sockaddr_in*)&saddr;
191	struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&saddr;
192	socklen_t socklen;
193	int ch, rv, on = 1, svcregcnt;
194	struct sigaction sa;
195	struct rlimit rlp;
196	pid_t child, pid;
197	sigset_t waitset, osigset;
198	int server_sig;
199
200	config = config_defaults;
201	config_read(&config);
202
203	while ((ch = getopt(argc, argv, "d:g:x:")) != (-1)) {
204		switch (ch) {
205		case 'd':
206			config.verbose = atoi(optarg);
207			break;
208		case 'g':
209			config.grace_period = atoi(optarg);
210			break;
211		case 'x':
212			config.host_monitor_cache_timeout = atoi(optarg);
213			break;
214		default:
215		case '?':
216			usage();
217			/* NOTREACHED */
218		}
219	}
220	if (geteuid()) { /* This command allowed only to root */
221		fprintf(stderr, "Sorry. You are not superuser\n");
222		exit(1);
223        }
224
225	/* Install signal handler to do cleanup */
226	signal(SIGINT, handle_sig_cleanup);
227	signal(SIGTERM, handle_sig_cleanup);
228	signal(SIGHUP, handle_sig_cleanup);
229	signal(SIGQUIT, handle_sig_cleanup);
230
231	openlog("rpc.lockd", LOG_CONS | LOG_PID | ((config.verbose == 99) ? LOG_PERROR : 0), LOG_DAEMON);
232
233	/* claim PID file */
234	pfh = pidfile_open(_PATH_LOCKD_PID, 0644, &pid);
235	if (pfh == NULL) {
236		syslog(LOG_ERR, "can't open lockd pidfile: %s (%d)", strerror(errno), errno);
237		if (errno == EEXIST) {
238			syslog(LOG_ERR, "lockd already running, pid: %d", pid);
239			exit(0);
240		}
241		exit(2);
242	}
243	if (pidfile_write(pfh) == -1)
244		syslog(LOG_WARNING, "can't write to lockd pidfile: %s (%d)", strerror(errno), errno);
245
246	if (config.verbose)
247		syslog(LOG_INFO, "lockd starting, debug level %d", config.verbose);
248	else
249		syslog(LOG_INFO, "lockd starting");
250
251	/* make sure statd is running */
252	if ((rv = statd_start()))
253		syslog(LOG_WARNING, "unable to start statd %d", rv);
254
255	/* Install signal handler to collect exit status of child processes */
256	sa.sa_handler = handle_sigchld;
257	sigemptyset(&sa.sa_mask);
258	sigaddset(&sa.sa_mask, SIGCHLD);
259	sa.sa_flags = SA_RESTART;
260	sigaction(SIGCHLD, &sa, NULL);
261
262	/*
263	 * Create a separate process, the client code is really a separate
264	 * daemon that shares a lot of code. We let the server be the child.
265	 * The reason for this is that child will get the receive right from
266	 * launchd and it is that process that launchd should be monitoring
267	 * We mask SIGUSR1 and then pause in the parent. When the child is
268	 * ready it will signal the parent to continue. In this way we know
269	 * that if we send a request out to some server, we have a server
270	 * process up to handle the reply.
271	 */
272
273	sigemptyset(&waitset);
274	sigaddset(&waitset, SIGUSR1);
275	sigaddset(&waitset, SIGCHLD);
276	sigaddset(&waitset, SIGINT);
277	sigaddset(&waitset, SIGTERM);
278	sigprocmask(SIG_BLOCK, &waitset, &osigset);
279	switch (child = fork()) {
280	case -1:
281		syslog(LOG_ERR, "Could not fork server");
282		handle_sig_cleanup(SIGQUIT);
283		/*NOTREACHED*/
284	case 0:
285		/* Server doesn't need to block */
286		sigprocmask(SIG_SETMASK, &osigset, NULL);
287		break;
288	default:
289		/* we're the parent and the client */
290		server_pid = child;
291		/* Wait for the server to be up */
292		sigwait(&waitset, &server_sig);
293		if (server_sig != SIGUSR1) {
294			syslog(LOG_ERR, "Lockd got unexpected signal %d\n", server_sig);
295			handle_sig_cleanup(SIGQUIT);
296		}
297		sigprocmask(SIG_SETMASK, &osigset, NULL); /* Reset signal mask */
298		client_mach_request();
299		/* We should never return, but if we do kill our other half */
300		syslog(LOG_ERR,	"Lockd: client_mach_request(), returned unexpectedly");
301		handle_sig_cleanup(SIGQUIT);
302		/*NOTREACHED*/
303	}
304
305	/* We're the child and the server */
306	lockudpsock = locktcpsock = -1;
307	lockudp6sock = locktcp6sock = -1;
308
309	rpcb_unset(NULL, NLM_PROG, NLM_SM);
310	rpcb_unset(NULL, NLM_PROG, NLM_VERS);
311	rpcb_unset(NULL, NLM_PROG, NLM_VERSX);
312	rpcb_unset(NULL, NLM_PROG, NLM_VERS4);
313
314	/* parent cleans up the pid file */
315	pfh = NULL;
316
317	if (config.udp) {
318
319		/* IPv4 */
320		if ((lockudpsock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
321			syslog(LOG_ERR, "can't create UDP IPv4 socket: %s (%d)", strerror(errno), errno);
322		if (lockudpsock >= 0) {
323			sin->sin_family = AF_INET;
324			sin->sin_addr.s_addr = INADDR_ANY;
325			sin->sin_port = htons(config.port);
326			sin->sin_len = sizeof(*sin);
327			if (bindresvport_sa(lockudpsock, (struct sockaddr *)sin) < 0) {
328				/* socket may still be lingering from previous incarnation */
329				/* wait a few seconds and try again */
330				sleep(6);
331				if (bindresvport_sa(lockudpsock, (struct sockaddr *)sin) < 0) {
332					syslog(LOG_ERR, "can't bind UDP IPv4 addr: %s (%d)", strerror(errno), errno);
333					close(lockudpsock);
334					lockudpsock = -1;
335				}
336			}
337		}
338		if (lockudpsock >= 0) {
339			socklen = sizeof(*sin);
340			if (getsockname(lockudpsock, (struct sockaddr *)sin, &socklen)) {
341				syslog(LOG_ERR, "can't getsockname on UDP IPv4 socket: %s (%d)", strerror(errno), errno);
342				close(lockudpsock);
343				lockudpsock = -1;
344			} else {
345				udpport = ntohs(sin->sin_port);
346			}
347		}
348		if ((lockudpsock >= 0) && ((transp = svcudp_create(lockudpsock)) == NULL)) {
349			syslog(LOG_ERR, "cannot create UDP IPv4 service");
350			close(lockudpsock);
351			lockudpsock = -1;
352		}
353		if (lockudpsock >= 0) {
354			svcregcnt = 0;
355			if (!svc_register(transp, NLM_PROG, NLM_SM, nlm_prog_0, IPPROTO_UDP))
356				syslog(LOG_ERR, "unable to register IPv4 (NLM_PROG, NLM_SM, udp)");
357			else
358				svcregcnt++;
359			if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP))
360				syslog(LOG_ERR, "unable to register IPv4 (NLM_PROG, NLM_VERS, udp)");
361			else
362				svcregcnt++;
363			if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP))
364				syslog(LOG_ERR, "unable to register IPv4 (NLM_PROG, NLM_VERSX, udp)");
365			else
366				svcregcnt++;
367			if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_UDP))
368				syslog(LOG_ERR, "unable to register IPv4 (NLM_PROG, NLM_VERS4, udp)");
369			else
370				svcregcnt++;
371			if (!svcregcnt) {
372				svc_destroy(transp);
373				close(lockudpsock);
374				lockudpsock = -1;
375			}
376		}
377
378		/* IPv6 */
379		if ((lockudp6sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
380			syslog(LOG_ERR, "can't create UDP IPv6 socket: %s (%d)", strerror(errno), errno);
381		if (lockudp6sock >= 0) {
382			setsockopt(lockudp6sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
383			sin6->sin6_family = AF_INET6;
384			sin6->sin6_addr = in6addr_any;
385			sin6->sin6_port = htons(config.port);
386			sin6->sin6_len = sizeof(*sin6);
387			if (bindresvport_sa(lockudp6sock, (struct sockaddr *)sin6) < 0) {
388				/* socket may still be lingering from previous incarnation */
389				/* wait a few seconds and try again */
390				sleep(6);
391				if (bindresvport_sa(lockudp6sock, (struct sockaddr *)sin6) < 0) {
392					syslog(LOG_ERR, "can't bind UDP IPv6 addr: %s (%d)", strerror(errno), errno);
393					close(lockudp6sock);
394					lockudp6sock = -1;
395				}
396			}
397		}
398		if (lockudp6sock >= 0) {
399			socklen = sizeof(*sin6);
400			if (getsockname(lockudp6sock, (struct sockaddr *)sin6, &socklen)) {
401				syslog(LOG_ERR, "can't getsockname on UDP IPv6 socket: %s (%d)", strerror(errno), errno);
402				close(lockudp6sock);
403				lockudp6sock = -1;
404			} else {
405				udp6port = ntohs(sin6->sin6_port);
406			}
407		}
408		if ((lockudp6sock >= 0) && ((transp = svcudp_create(lockudp6sock)) == NULL)) {
409			syslog(LOG_ERR, "cannot create UDP IPv6 service");
410			close(lockudp6sock);
411			lockudp6sock = -1;
412		}
413		if (lockudp6sock >= 0) {
414			svcregcnt = 0;
415			if (!svc_register(transp, NLM_PROG, NLM_SM, nlm_prog_0, IPPROTO_UDP))
416				syslog(LOG_ERR, "unable to register IPv6 (NLM_PROG, NLM_SM, udp)");
417			else
418				svcregcnt++;
419			if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_UDP))
420				syslog(LOG_ERR, "unable to register IPv6 (NLM_PROG, NLM_VERS, udp)");
421			else
422				svcregcnt++;
423			if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_UDP))
424				syslog(LOG_ERR, "unable to register IPv6 (NLM_PROG, NLM_VERSX, udp)");
425			else
426				svcregcnt++;
427			if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_UDP))
428				syslog(LOG_ERR, "unable to register IPv6 (NLM_PROG, NLM_VERS4, udp)");
429			else
430				svcregcnt++;
431			if (!svcregcnt) {
432				svc_destroy(transp);
433				close(lockudp6sock);
434				lockudp6sock = -1;
435			}
436		}
437
438	}
439
440	if (config.tcp) {
441
442		/* IPv4 */
443		if ((locktcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
444			syslog(LOG_ERR, "can't create TCP IPv4 socket: %s (%d)", strerror(errno), errno);
445		if (locktcpsock >= 0) {
446			if (setsockopt(locktcpsock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
447				syslog(LOG_WARNING, "setsockopt TCP IPv4 SO_REUSEADDR: %s (%d)", strerror(errno), errno);
448			sin->sin_family = AF_INET;
449			sin->sin_addr.s_addr = INADDR_ANY;
450			sin->sin_port = htons(config.port);
451			sin->sin_len = sizeof(*sin);
452			if (bindresvport_sa(locktcpsock, (struct sockaddr *)sin) < 0) {
453				syslog(LOG_ERR, "can't bind TCP IPv4 addr: %s (%d)", strerror(errno), errno);
454				close(locktcpsock);
455				locktcpsock = -1;
456			}
457		}
458		if (locktcpsock >= 0) {
459			socklen = sizeof(*sin);
460			if (getsockname(locktcpsock, (struct sockaddr *)sin, &socklen)) {
461				syslog(LOG_ERR, "can't getsockname on TCP IPv4 socket: %s (%d)", strerror(errno), errno);
462				close(locktcpsock);
463				locktcpsock = -1;
464			} else {
465				tcpport = ntohs(sin->sin_port);
466			}
467		}
468		if ((locktcpsock >= 0) && ((transp = svctcp_create(locktcpsock, 0, 0)) == NULL)) {
469			syslog(LOG_ERR, "cannot create TCP IPv4 service");
470			close(locktcpsock);
471			locktcpsock = -1;
472		}
473		if (locktcpsock >= 0) {
474			svcregcnt = 0;
475			if (!svc_register(transp, NLM_PROG, NLM_SM, nlm_prog_0, IPPROTO_TCP))
476				syslog(LOG_ERR, "unable to register IPv4 (NLM_PROG, NLM_SM, tcp)");
477			else
478				svcregcnt++;
479			if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP))
480				syslog(LOG_ERR, "unable to register IPv4 (NLM_PROG, NLM_VERS, tcp)");
481			else
482				svcregcnt++;
483			if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP))
484				syslog(LOG_ERR, "unable to register IPv4 (NLM_PROG, NLM_VERSX, tcp)");
485			else
486				svcregcnt++;
487			if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_TCP))
488				syslog(LOG_ERR, "unable to register IPv4 (NLM_PROG, NLM_VERS4, tcp)");
489			else
490				svcregcnt++;
491			if (!svcregcnt) {
492				svc_destroy(transp);
493				close(locktcpsock);
494				locktcpsock = -1;
495			}
496		}
497
498		/* IPv6 */
499		if ((locktcp6sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
500			syslog(LOG_ERR, "can't create TCP IPv6 socket: %s (%d)", strerror(errno), errno);
501		if (locktcp6sock >= 0) {
502			if (setsockopt(locktcp6sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
503				syslog(LOG_WARNING, "setsockopt TCP IPv6 SO_REUSEADDR: %s (%d)", strerror(errno), errno);
504			setsockopt(locktcp6sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
505			sin6->sin6_family = AF_INET6;
506			sin6->sin6_addr = in6addr_any;
507			sin6->sin6_port = htons(config.port);
508			sin6->sin6_len = sizeof(*sin6);
509			if (bindresvport_sa(locktcp6sock, (struct sockaddr *)sin6) < 0) {
510				syslog(LOG_ERR, "can't bind TCP IPv6 addr: %s (%d)", strerror(errno), errno);
511				close(locktcp6sock);
512				locktcp6sock = -1;
513			}
514		}
515		if (locktcp6sock >= 0) {
516			socklen = sizeof(*sin6);
517			if (getsockname(locktcp6sock, (struct sockaddr *)sin6, &socklen)) {
518				syslog(LOG_ERR, "can't getsockname on TCP IPv6 socket: %s (%d)", strerror(errno), errno);
519				close(locktcp6sock);
520				locktcp6sock = -1;
521			} else {
522				tcp6port = ntohs(sin6->sin6_port);
523			}
524		}
525		if ((locktcp6sock >= 0) && ((transp = svctcp_create(locktcp6sock, 0, 0)) == NULL)) {
526			syslog(LOG_ERR, "cannot create TCP IPv6 service");
527			close(locktcp6sock);
528			locktcp6sock = -1;
529		}
530		if (locktcp6sock >= 0) {
531			svcregcnt = 0;
532			if (!svc_register(transp, NLM_PROG, NLM_SM, nlm_prog_0, IPPROTO_TCP))
533				syslog(LOG_ERR, "unable to register IPv6 (NLM_PROG, NLM_SM, tcp)");
534			else
535				svcregcnt++;
536			if (!svc_register(transp, NLM_PROG, NLM_VERS, nlm_prog_1, IPPROTO_TCP))
537				syslog(LOG_ERR, "unable to register IPv6 (NLM_PROG, NLM_VERS, tcp)");
538			else
539				svcregcnt++;
540			if (!svc_register(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, IPPROTO_TCP))
541				syslog(LOG_ERR, "unable to register IPv6 (NLM_PROG, NLM_VERSX, tcp)");
542			else
543				svcregcnt++;
544			if (!svc_register(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, IPPROTO_TCP))
545				syslog(LOG_ERR, "unable to register IPv6 (NLM_PROG, NLM_VERS4, tcp)");
546			else
547				svcregcnt++;
548			if (!svcregcnt) {
549				svc_destroy(transp);
550				close(locktcp6sock);
551				locktcp6sock = -1;
552			}
553		}
554
555	}
556
557	if ((lockudp6sock < 0) && (locktcp6sock < 0))
558		syslog(LOG_WARNING, "Can't create NLM IPv6 sockets");
559	if ((lockudpsock < 0) && (locktcpsock < 0))
560		syslog(LOG_WARNING, "Can't create NLM IPv4 sockets");
561	if ((lockudp6sock < 0) && (locktcp6sock < 0) &&
562	    (lockudpsock < 0) && (locktcpsock < 0)) {
563		syslog(LOG_ERR, "Can't create any NLM sockets!");
564		exit(1);
565	}
566
567	init_nsm();
568
569	/* raise our resource limits as far as they can go */
570	if (getrlimit(RLIMIT_NOFILE, &rlp)) {
571		syslog(LOG_WARNING, "getrlimit(RLIMIT_NOFILE) failed: %s",
572			strerror(errno));
573	} else {
574		rlp.rlim_cur = MIN(rlp.rlim_max, 2*FD_SETSIZE);
575		if (setrlimit(RLIMIT_NOFILE, &rlp)) {
576			syslog(LOG_WARNING, "setrlimit(RLIMIT_NOFILE) failed: %s",
577				strerror(errno));
578		}
579	}
580
581	/* set up grace period alarm */
582	sa.sa_handler = (sig_t) sigalarm_grace_period_handler;
583	sigemptyset(&sa.sa_mask);
584	sa.sa_flags = SA_RESETHAND; /* should only happen once */
585	sa.sa_flags |= SA_RESTART;
586	if (sigaction(SIGALRM, &sa, NULL) != 0) {
587		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
588		    strerror(errno));
589		exit(1);
590	}
591	if (config.grace_period > 0) {
592		grace_expired = 0;
593		alarm(config.grace_period);
594	} else {
595		grace_expired = 1;
596	}
597
598	/* Signal the parent (client process) that its ok to start */
599	kill(getppid(), SIGUSR1);
600
601	my_svc_run();		/* Should never return */
602	exit(1);
603}
604
605void
606sigalarm_grace_period_handler(void)
607{
608	grace_expired = 1;
609}
610
611void
612usage()
613{
614	errx(1, "usage: rpc.lockd [-d <debuglevel>] [-g <grace period>] "
615	    " [-x <host monitor cache timeout>] [-w]");
616}
617
618/*
619 * init_nsm --
620 *	Reset the NSM state-of-the-world and acquire its state.
621 */
622void
623init_nsm(void)
624{
625	enum clnt_stat ret;
626	sm_stat mstat;
627	char localhost[] = "localhost";
628	int attempt = 0;
629
630	/* setup constant data for SM_MON calls */
631	mon_host.mon_id.my_id.my_name = localhost;
632	mon_host.mon_id.my_id.my_prog = NLM_PROG;
633	mon_host.mon_id.my_id.my_vers = NLM_SM;
634	mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
635
636	/*
637	 * !!!
638	 * The statd program must already be registered when lockd runs.
639	 * If we have a problem contacting statd, pause and try again a
640	 * number of times in case statd is just slow in coming up.
641	 */
642	do {
643		ret = callrpc((char *) "localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
644		    (xdrproc_t)xdr_my_id, &mon_host.mon_id.my_id, (xdrproc_t)xdr_sm_stat, &mstat);
645		if (ret) {
646			syslog(LOG_WARNING, "can't contact statd, %u %s", SM_PROG, clnt_sperrno(ret));
647			if (++attempt < 20) {
648				/* attempt to start it again */
649				statd_start();
650				sleep(attempt);
651				continue;
652			}
653		}
654		break;
655	} while (1);
656
657	if (ret != 0) {
658		syslog(LOG_ERR, "server init_nsm failed! %u %s", SM_PROG, clnt_sperrno(ret));
659		exit(1);
660	}
661
662	nsm_state = mstat.state;
663
664}
665
666/*
667 * handle_sig_cleanup
668 *
669 * Purpose:	on signal, kill server child and do pid file cleanup
670 * Returns:	Nothing
671 */
672void
673handle_sig_cleanup(int sig)
674{
675	pid_t pid;
676	int status;
677
678	if (server_pid != -1) {
679		pid = server_pid;
680		server_pid = -1;
681		kill(pid, SIGTERM);
682		wait4(pid, &status, 0, NULL);
683	} else {
684		alarm(1); /* XXX 5028243 in case rpcb_unset() gets hung up during shutdown */
685		rpcb_unset(NULL, NLM_PROG, NLM_SM);
686		rpcb_unset(NULL, NLM_PROG, NLM_VERS);
687		rpcb_unset(NULL, NLM_PROG, NLM_VERSX);
688		rpcb_unset(NULL, NLM_PROG, NLM_VERS4);
689	}
690	if (pfh && !sig)
691		pidfile_remove(pfh);
692	exit(!sig ? 0 : 1);
693}
694
695/*
696 * handle_sigchld
697 *
698 * Exit if we catch the lockd server child process dying.
699 */
700static void
701handle_sigchld(int sig __unused)
702{
703	pid_t pid;
704	int status;
705
706	pid = wait4(-1, &status, WNOHANG, NULL);
707	if ((server_pid != -1) && (pid == server_pid)) {
708		if (status)
709			syslog(LOG_ERR, "lockd server %d failed with status %d",
710				pid, WEXITSTATUS(status));
711		handle_sig_cleanup(SIGCHLD);
712		/*NOTREACHED*/
713	}
714}
715
716/*
717 * The RPC service run loop
718 */
719void
720my_svc_run(void)
721{
722        fd_set readfds;
723        struct timeval timeout;
724	struct timeval now;
725	int error;
726	int hashosts = 0;
727	struct timeval *top;
728	extern int svc_maxfd;
729
730
731	for( ;; ) {
732		timeout.tv_sec = config.host_monitor_cache_timeout + 1;
733		timeout.tv_usec = 0;
734
735		bcopy(&svc_fdset, &readfds, sizeof(svc_fdset));
736		/*
737		 * If there are any expired hosts then sleep with a
738		 * timeout to expire them.
739		 */
740		if (hashosts && (timeout.tv_sec >= 0))
741			top = &timeout;
742		else
743			top = NULL;
744		error = select(svc_maxfd+1, &readfds, NULL, NULL, top);
745		if (error == -1) {
746			if (errno == EINTR)
747				continue;
748                        perror("rpc.lockd: my_svc_run: select failed");
749                        return;
750		}
751		gettimeofday(&now, NULL);
752		currsec = now.tv_sec;
753		if (error > 0)
754			svc_getreqset(&readfds);
755		if ((config.verbose > 3) && (error == 0))
756			fprintf(stderr, "my_svc_run: select timeout\n");
757		hashosts = expire_lock_hosts();
758	}
759}
760
761/*
762 * read the lockd values from nfs.conf
763 */
764static int
765config_read(struct nfs_conf_lockd *conf)
766{
767	FILE *f;
768	size_t len, linenum = 0;
769	char *line, *p, *key, *value;
770	long val;
771
772	if (!(f = fopen(_PATH_NFS_CONF, "r"))) {
773		if (errno != ENOENT)
774			syslog(LOG_WARNING, "%s", _PATH_NFS_CONF);
775		return (1);
776	}
777	for (; (line = fparseln(f, &len, &linenum, NULL, 0)); free(line)) {
778		if (len <= 0)
779			continue;
780		/* trim trailing whitespace */
781		p = line + len - 1;
782		while ((p > line) && isspace(*p))
783			*p-- = '\0';
784		/* find key start */
785		key = line;
786		while (isspace(*key))
787			key++;
788		/* find equals/value */
789		value = p = strchr(line, '=');
790		if (p) /* trim trailing whitespace on key */
791			do { *p-- = '\0'; } while ((p > line) && isspace(*p));
792		/* find value start */
793		if (value)
794			do { value++; } while (isspace(*value));
795
796		/* all lockd keys start with "nfs.lockd." */
797		if (strncmp(key, "nfs.lockd.", 10)) {
798			if (config.verbose)
799				syslog(LOG_DEBUG, "%4ld %s=%s\n", linenum, key, value ? value : "");
800			continue;
801		}
802		val = !value ? 1 : strtol(value, NULL, 0);
803		if (config.verbose)
804			syslog(LOG_DEBUG, "%4ld %s=%s (%ld)\n", linenum, key, value ? value : "", val);
805
806		if (!strcmp(key, "nfs.lockd.grace_period")) {
807			if (value && val)
808				conf->grace_period = val;
809		} else if (!strcmp(key, "nfs.lockd.host_monitor_cache_timeout")) {
810			if (value)
811				conf->host_monitor_cache_timeout = val;
812		} else if (!strcmp(key, "nfs.lockd.port")) {
813			if (value && val)
814				conf->port = val;
815		} else if (!strcmp(key, "nfs.lockd.send_using_tcp")) {
816			conf->send_using_tcp = val;
817		} else if (!strcmp(key, "nfs.lockd.send_using_mnt_transport")) {
818			conf->send_using_mnt_transport = val;
819		} else if (!strcmp(key, "nfs.lockd.shutdown_delay_client")) {
820			if (value && val)
821				conf->shutdown_delay_client = val;
822		} else if (!strcmp(key, "nfs.lockd.shutdown_delay_server")) {
823			if (value && val)
824				conf->shutdown_delay_server = val;
825		} else if (!strcmp(key, "nfs.lockd.tcp")) {
826			conf->tcp = val;
827		} else if (!strcmp(key, "nfs.lockd.udp")) {
828			conf->udp = val;
829		} else if (!strcmp(key, "nfs.lockd.verbose")) {
830			conf->verbose = val;
831		} else {
832			if (config.verbose)
833				syslog(LOG_DEBUG, "ignoring unknown config value: %4ld %s=%s\n", linenum, key, value ? value : "");
834		}
835
836	}
837
838	fclose(f);
839	return (0);
840}
841
842/*
843 * get the PID of the running statd
844 */
845static pid_t
846get_statd_pid(void)
847{
848	char pidbuf[128], *pidend;
849	int fd, len, rv;
850	pid_t pid;
851	struct flock lock;
852
853	if ((fd = open(_PATH_STATD_PID, O_RDONLY)) < 0) {
854		if (config.verbose)
855			syslog(LOG_DEBUG, "%s: %s (%d)", _PATH_STATD_PID, strerror(errno), errno);
856		return (0);
857	}
858	len = sizeof(pidbuf) - 1;
859	if ((len = read(fd, pidbuf, len)) < 0) {
860		if (config.verbose)
861			syslog(LOG_DEBUG, "%s: %s (%d)", _PATH_STATD_PID, strerror(errno), errno);
862		return (0);
863	}
864
865	/* parse PID */
866	pidbuf[len] = '\0';
867	pid = strtol(pidbuf, &pidend, 10);
868	if (!len || (pid < 1)) {
869		if (config.verbose)
870			syslog(LOG_DEBUG, "%s: bogus pid: %s", _PATH_STATD_PID, pidbuf);
871		return (0);
872	}
873
874	/* check for lock on file by PID */
875	lock.l_type = F_RDLCK;
876	lock.l_whence = SEEK_SET;
877	lock.l_start = 0;
878	lock.l_len = 0;
879	rv = fcntl(fd, F_GETLK, &lock);
880	close(fd);
881	if (rv != 0) {
882		if (config.verbose)
883			syslog(LOG_DEBUG, "%s: fcntl: %s (%d)", _PATH_STATD_PID, strerror(errno), errno);
884		return (0);
885	} else if (lock.l_type == F_UNLCK) {
886		if (config.verbose)
887			syslog(LOG_DEBUG, "%s: not locked\n", _PATH_STATD_PID);
888		return (0);
889	}
890	return (pid);
891}
892
893static int
894statd_is_running(void)
895{
896	return (get_statd_pid() > 0);
897}
898
899static int
900statd_is_loaded(void)
901{
902	launch_data_t msg, resp;
903	int rv = 0;
904
905	msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
906	if (!msg)
907		return (0);
908	launch_data_dict_insert(msg, launch_data_new_string(_STATD_SERVICE_LABEL), LAUNCH_KEY_GETJOB);
909
910	resp = launch_msg(msg);
911	if (resp) {
912		if (launch_data_get_type(resp) == LAUNCH_DATA_DICTIONARY)
913			rv = 1;
914		launch_data_free(resp);
915	} else {
916		syslog(LOG_ERR, "launch_msg(): %m");
917	}
918
919	launch_data_free(msg);
920	return (rv);
921}
922
923static int
924statd_load(void)
925{
926	launch_data_t msg, job, args, resp;
927	int rv = 1;
928
929	msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
930	job = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
931	args = launch_data_alloc(LAUNCH_DATA_ARRAY);
932	if (!msg || !job || !args) {
933		if (msg) launch_data_free(msg);
934		if (job) launch_data_free(job);
935		if (args) launch_data_free(args);
936		return (1);
937	}
938	launch_data_array_set_index(args, launch_data_new_string(_PATH_STATD), 0);
939	launch_data_dict_insert(job, launch_data_new_string(_STATD_SERVICE_LABEL), LAUNCH_JOBKEY_LABEL);
940	launch_data_dict_insert(job, launch_data_new_bool(FALSE), LAUNCH_JOBKEY_ONDEMAND);
941	launch_data_dict_insert(job, launch_data_new_bool(TRUE), LAUNCH_JOBKEY_HOPEFULLYEXITSLAST);
942	launch_data_dict_insert(job, args, LAUNCH_JOBKEY_PROGRAMARGUMENTS);
943	launch_data_dict_insert(msg, job, LAUNCH_KEY_SUBMITJOB);
944
945	resp = launch_msg(msg);
946	if (!resp) {
947		rv = errno;
948	} else {
949		if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO)
950			rv = launch_data_get_errno(resp);
951		launch_data_free(resp);
952	}
953
954	launch_data_free(msg);
955	return (rv);
956}
957
958static int
959statd_service_start(void)
960{
961	launch_data_t msg, resp;
962	int rv = 1;
963
964	msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
965	if (!msg)
966		return (1);
967	launch_data_dict_insert(msg, launch_data_new_string(_STATD_SERVICE_LABEL), LAUNCH_KEY_STARTJOB);
968
969	resp = launch_msg(msg);
970	if (!resp) {
971		rv = errno;
972	} else {
973		if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO)
974			rv = launch_data_get_errno(resp);
975		launch_data_free(resp);
976	}
977
978	launch_data_free(msg);
979	return (rv);
980}
981
982int
983statd_start(void)
984{
985	struct timespec ts;
986	int rv;
987
988	if (statd_is_running())
989		rv = 0;
990	else if (statd_is_loaded())
991		rv = statd_service_start();
992	else
993		rv = statd_load();
994
995	/* sleep a little to give statd/portmap a chance to start */
996	/* (better to sleep 100ms than to timeout on portmap calls) */
997	ts.tv_sec = 0;
998	ts.tv_nsec = 100*1000*1000;
999	nanosleep(&ts, NULL);
1000
1001	return (rv);
1002}
1003
1004int
1005statd_stop(void)
1006{
1007	launch_data_t msg, resp;
1008	int rv = 1;
1009
1010	msg = launch_data_alloc(LAUNCH_DATA_DICTIONARY);
1011	if (!msg)
1012		return (1);
1013	launch_data_dict_insert(msg, launch_data_new_string(_STATD_SERVICE_LABEL), LAUNCH_KEY_REMOVEJOB);
1014
1015	resp = launch_msg(msg);
1016	if (!resp) {
1017		rv = errno;
1018	} else {
1019		if (launch_data_get_type(resp) == LAUNCH_DATA_ERRNO)
1020			rv = launch_data_get_errno(resp);
1021		launch_data_free(resp);
1022	}
1023
1024	launch_data_free(msg);
1025	return (rv);
1026}
1027
1028