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