1 /* $NetBSD: nfsd.c,v 1.57 2009/12/21 05:06:55 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\ 38 The Regents of the University of California. All rights reserved."); 39 #endif /* not lint */ 40 41 #ifndef lint 42 #if 0 43 static char sccsid[] = "@(#)nfsd.c 8.9 (Berkeley) 3/29/95"; 44 #else 45 __RCSID("$NetBSD: nfsd.c,v 1.57 2009/12/21 05:06:55 christos Exp $"); 46 #endif 47 #endif /* not lint */ 48 49 #include <sys/param.h> 50 #include <sys/ioctl.h> 51 #include <sys/stat.h> 52 #include <sys/wait.h> 53 #include <sys/uio.h> 54 #include <sys/ucred.h> 55 #include <sys/mount.h> 56 #include <sys/socket.h> 57 #include <sys/socketvar.h> 58 #include <poll.h> 59 60 #include <rpc/rpc.h> 61 #include <rpc/pmap_clnt.h> 62 #include <rpc/pmap_prot.h> 63 64 #include <nfs/rpcv2.h> 65 #include <nfs/nfsproto.h> 66 #include <nfs/nfs.h> 67 68 #include <err.h> 69 #include <errno.h> 70 #include <fcntl.h> 71 #include <grp.h> 72 #include <pwd.h> 73 #include <pthread.h> 74 #include <signal.h> 75 #include <stdio.h> 76 #include <stdlib.h> 77 #include <string.h> 78 #include <syslog.h> 79 #include <unistd.h> 80 #include <netdb.h> 81 82 /* Global defs */ 83 #ifdef DEBUG 84 #define syslog(e, s, args...) \ 85 do { \ 86 fprintf(stderr,(s), ## args); \ 87 fprintf(stderr, "\n"); \ 88 } while (/*CONSTCOND*/0) 89 int debug = 1; 90 #else 91 int debug = 0; 92 #endif 93 94 int main __P((int, char **)); 95 void nonfs __P((int)); 96 void usage __P((void)); 97 98 static void * 99 worker(void *dummy) 100 { 101 struct nfsd_srvargs nsd; 102 int nfssvc_flag; 103 104 pthread_setname_np(pthread_self(), "slave", NULL); 105 nfssvc_flag = NFSSVC_NFSD; 106 memset(&nsd, 0, sizeof(nsd)); 107 while (nfssvc(nfssvc_flag, &nsd) < 0) { 108 if (errno != ENEEDAUTH) { 109 syslog(LOG_ERR, "nfssvc: %m"); 110 exit(1); 111 } 112 nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL; 113 } 114 115 return NULL; 116 } 117 118 /* 119 * Nfs server daemon mostly just a user context for nfssvc() 120 * 121 * 1 - do file descriptor and signal cleanup 122 * 2 - create the nfsd thread(s) 123 * 3 - create server socket(s) 124 * 4 - register socket with portmap 125 * 126 * For connectionless protocols, just pass the socket into the kernel via 127 * nfssvc(). 128 * For connection based sockets, loop doing accepts. When you get a new 129 * socket from accept, pass the msgsock into the kernel via nfssvc(). 130 * The arguments are: 131 * -c - support iso cltp clients 132 * -r - reregister with portmapper 133 * -t - support tcp nfs clients 134 * -u - support udp nfs clients 135 * followed by "n" which is the number of nfsd threads to create 136 */ 137 int 138 main(argc, argv) 139 int argc; 140 char *argv[]; 141 { 142 struct nfsd_args nfsdargs; 143 struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints; 144 struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6; 145 struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6; 146 struct sockaddr_in inetpeer; 147 struct sockaddr_in6 inet6peer; 148 struct pollfd set[4]; 149 socklen_t len; 150 int ch, cltpflag, connect_type_cnt, i, maxsock, msgsock, serrno; 151 int nfsdcnt, on = 1, reregister, sock, tcpflag, tcpsock; 152 int tcp6sock, ip6flag; 153 int tp4cnt, tp4flag, tpipcnt, tpipflag, udpflag, ecode, s; 154 155 #define DEFNFSDCNT 4 156 nfsdcnt = DEFNFSDCNT; 157 cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0; 158 tpipflag = udpflag = ip6flag = 0; 159 nconf_udp = nconf_tcp = nconf_udp6 = nconf_tcp6 = NULL; 160 maxsock = 0; 161 tcpsock = tcp6sock = -1; 162 #define GETOPT "6n:rtu" 163 #define USAGE "[-rtu] [-n num_servers]" 164 while ((ch = getopt(argc, argv, GETOPT)) != -1) { 165 switch (ch) { 166 case '6': 167 ip6flag = 1; 168 s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); 169 if (s < 0 && (errno == EPROTONOSUPPORT || 170 errno == EPFNOSUPPORT || errno == EAFNOSUPPORT)) 171 ip6flag = 0; 172 else 173 close(s); 174 break; 175 case 'n': 176 nfsdcnt = atoi(optarg); 177 if (nfsdcnt < 1) { 178 warnx("nfsd count %d; reset to %d", nfsdcnt, DEFNFSDCNT); 179 nfsdcnt = DEFNFSDCNT; 180 } 181 break; 182 case 'r': 183 reregister = 1; 184 break; 185 case 't': 186 tcpflag = 1; 187 break; 188 case 'u': 189 udpflag = 1; 190 break; 191 default: 192 case '?': 193 usage(); 194 }; 195 } 196 argv += optind; 197 argc -= optind; 198 199 /* 200 * XXX 201 * Backward compatibility, trailing number is the count of daemons. 202 */ 203 if (argc > 1) 204 usage(); 205 if (argc == 1) { 206 nfsdcnt = atoi(argv[0]); 207 if (nfsdcnt < 1) { 208 warnx("nfsd count %d; reset to %d", nfsdcnt, DEFNFSDCNT); 209 nfsdcnt = DEFNFSDCNT; 210 } 211 } 212 213 /* 214 * If none of TCP or UDP are specified, default to UDP only. 215 */ 216 if (tcpflag == 0 && udpflag == 0) 217 udpflag = 1; 218 219 if (debug == 0) { 220 daemon(0, 0); 221 (void)signal(SIGHUP, SIG_IGN); 222 (void)signal(SIGINT, SIG_IGN); 223 (void)signal(SIGQUIT, SIG_IGN); 224 (void)signal(SIGSYS, nonfs); 225 } 226 227 if (udpflag) { 228 memset(&hints, 0, sizeof hints); 229 hints.ai_flags = AI_PASSIVE; 230 hints.ai_family = PF_INET; 231 hints.ai_socktype = SOCK_DGRAM; 232 hints.ai_protocol = IPPROTO_UDP; 233 234 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); 235 if (ecode != 0) { 236 syslog(LOG_ERR, "getaddrinfo udp: %s", 237 gai_strerror(ecode)); 238 exit(1); 239 } 240 241 nconf_udp = getnetconfigent("udp"); 242 243 if (nconf_udp == NULL) 244 err(1, "getnetconfigent udp failed"); 245 246 nb_udp.buf = ai_udp->ai_addr; 247 nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; 248 if (reregister) 249 if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) 250 err(1, "rpcb_set udp failed"); 251 } 252 253 if (tcpflag) { 254 memset(&hints, 0, sizeof hints); 255 hints.ai_flags = AI_PASSIVE; 256 hints.ai_family = PF_INET; 257 hints.ai_socktype = SOCK_STREAM; 258 hints.ai_protocol = IPPROTO_TCP; 259 260 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp); 261 if (ecode != 0) { 262 syslog(LOG_ERR, "getaddrinfo tcp: %s", 263 gai_strerror(ecode)); 264 exit(1); 265 } 266 267 nconf_tcp = getnetconfigent("tcp"); 268 269 if (nconf_tcp == NULL) 270 err(1, "getnetconfigent tcp failed"); 271 272 nb_tcp.buf = ai_tcp->ai_addr; 273 nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; 274 if (reregister) 275 if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) 276 err(1, "rpcb_set tcp failed"); 277 } 278 279 if (udpflag && ip6flag) { 280 memset(&hints, 0, sizeof hints); 281 hints.ai_flags = AI_PASSIVE; 282 hints.ai_family = PF_INET6; 283 hints.ai_socktype = SOCK_DGRAM; 284 hints.ai_protocol = IPPROTO_UDP; 285 286 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); 287 if (ecode != 0) { 288 syslog(LOG_ERR, "getaddrinfo udp: %s", 289 gai_strerror(ecode)); 290 exit(1); 291 } 292 293 nconf_udp6 = getnetconfigent("udp6"); 294 295 if (nconf_udp6 == NULL) 296 err(1, "getnetconfigent udp6 failed"); 297 298 nb_udp6.buf = ai_udp6->ai_addr; 299 nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; 300 if (reregister) 301 if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) 302 err(1, "rpcb_set udp6 failed"); 303 } 304 305 if (tcpflag && ip6flag) { 306 memset(&hints, 0, sizeof hints); 307 hints.ai_flags = AI_PASSIVE; 308 hints.ai_family = PF_INET6; 309 hints.ai_socktype = SOCK_STREAM; 310 hints.ai_protocol = IPPROTO_TCP; 311 312 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); 313 if (ecode != 0) { 314 syslog(LOG_ERR, "getaddrinfo tcp: %s", 315 gai_strerror(ecode)); 316 exit(1); 317 } 318 319 nconf_tcp6 = getnetconfigent("tcp6"); 320 321 if (nconf_tcp6 == NULL) 322 err(1, "getnetconfigent tcp6 failed"); 323 324 nb_tcp6.buf = ai_tcp6->ai_addr; 325 nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; 326 if (reregister) 327 if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) 328 err(1, "rpcb_set tcp6 failed"); 329 } 330 331 openlog("nfsd", LOG_PID, LOG_DAEMON); 332 333 for (i = 0; i < nfsdcnt; i++) { 334 pthread_t t; 335 int error; 336 337 error = pthread_create(&t, NULL, worker, NULL); 338 if (error) { 339 errno = error; 340 syslog(LOG_ERR, "pthread_create: %m"); 341 exit (1); 342 } 343 } 344 345 /* If we are serving udp, set up the socket. */ 346 if (udpflag) { 347 if ((sock = socket(ai_udp->ai_family, ai_udp->ai_socktype, 348 ai_udp->ai_protocol)) < 0) { 349 syslog(LOG_ERR, "can't create udp socket"); 350 exit(1); 351 } 352 if (bind(sock, ai_udp->ai_addr, ai_udp->ai_addrlen) < 0) { 353 syslog(LOG_ERR, "can't bind udp addr"); 354 exit(1); 355 } 356 if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp) || 357 !rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)) { 358 syslog(LOG_ERR, "can't register with udp portmap"); 359 exit(1); 360 } 361 nfsdargs.sock = sock; 362 nfsdargs.name = NULL; 363 nfsdargs.namelen = 0; 364 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { 365 syslog(LOG_ERR, "can't add UDP socket"); 366 exit(1); 367 } 368 (void)close(sock); 369 } 370 371 if (udpflag &&ip6flag) { 372 if ((sock = socket(ai_udp6->ai_family, ai_udp6->ai_socktype, 373 ai_udp6->ai_protocol)) < 0) { 374 syslog(LOG_ERR, "can't create udp socket"); 375 exit(1); 376 } 377 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 378 &on, sizeof on) < 0) { 379 syslog(LOG_ERR, "can't set v6-only binding for udp6 " 380 "socket: %m"); 381 exit(1); 382 } 383 if (bind(sock, ai_udp6->ai_addr, ai_udp6->ai_addrlen) < 0) { 384 syslog(LOG_ERR, "can't bind udp addr"); 385 exit(1); 386 } 387 if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6) || 388 !rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)) { 389 syslog(LOG_ERR, "can't register with udp portmap"); 390 exit(1); 391 } 392 nfsdargs.sock = sock; 393 nfsdargs.name = NULL; 394 nfsdargs.namelen = 0; 395 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { 396 syslog(LOG_ERR, "can't add UDP6 socket"); 397 exit(1); 398 } 399 (void)close(sock); 400 } 401 402 /* Now set up the master server socket waiting for tcp connections. */ 403 on = 1; 404 connect_type_cnt = 0; 405 if (tcpflag) { 406 if ((tcpsock = socket(ai_tcp->ai_family, ai_tcp->ai_socktype, 407 ai_tcp->ai_protocol)) < 0) { 408 syslog(LOG_ERR, "can't create tcp socket"); 409 exit(1); 410 } 411 if (setsockopt(tcpsock, 412 SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) 413 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); 414 if (bind(tcpsock, ai_tcp->ai_addr, ai_tcp->ai_addrlen) < 0) { 415 syslog(LOG_ERR, "can't bind tcp addr"); 416 exit(1); 417 } 418 if (listen(tcpsock, 5) < 0) { 419 syslog(LOG_ERR, "listen failed"); 420 exit(1); 421 } 422 if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp) || 423 !rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)) { 424 syslog(LOG_ERR, "can't register tcp with rpcbind"); 425 exit(1); 426 } 427 set[0].fd = tcpsock; 428 set[0].events = POLLIN; 429 connect_type_cnt++; 430 } else 431 set[0].fd = -1; 432 433 if (tcpflag && ip6flag) { 434 if ((tcp6sock = socket(ai_tcp6->ai_family, ai_tcp6->ai_socktype, 435 ai_tcp6->ai_protocol)) < 0) { 436 syslog(LOG_ERR, "can't create tcp socket"); 437 exit(1); 438 } 439 if (setsockopt(tcp6sock, 440 SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) 441 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); 442 if (setsockopt(tcp6sock, IPPROTO_IPV6, IPV6_V6ONLY, 443 &on, sizeof on) < 0) { 444 syslog(LOG_ERR, "can't set v6-only binding for tcp6 " 445 "socket: %m"); 446 exit(1); 447 } 448 if (bind(tcp6sock, ai_tcp6->ai_addr, ai_tcp6->ai_addrlen) < 0) { 449 syslog(LOG_ERR, "can't bind tcp6 addr"); 450 exit(1); 451 } 452 if (listen(tcp6sock, 5) < 0) { 453 syslog(LOG_ERR, "listen failed"); 454 exit(1); 455 } 456 if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6) || 457 !rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)) { 458 syslog(LOG_ERR, "can't register tcp6 with rpcbind"); 459 exit(1); 460 } 461 set[1].fd = tcp6sock; 462 set[1].events = POLLIN; 463 connect_type_cnt++; 464 } else 465 set[1].fd = -1; 466 467 set[2].fd = -1; 468 set[3].fd = -1; 469 470 if (connect_type_cnt == 0) 471 exit(0); 472 473 pthread_setname_np(pthread_self(), "master", NULL); 474 475 /* 476 * Loop forever accepting connections and passing the sockets 477 * into the kernel for the mounts. 478 */ 479 for (;;) { 480 if (poll(set, 4, INFTIM) < 1) { 481 syslog(LOG_ERR, "poll failed: %m"); 482 exit(1); 483 } 484 485 if (set[0].revents & POLLIN) { 486 len = sizeof(inetpeer); 487 if ((msgsock = accept(tcpsock, 488 (struct sockaddr *)&inetpeer, &len)) < 0) { 489 serrno = errno; 490 syslog(LOG_ERR, "accept failed: %m"); 491 if (serrno == EINTR || serrno == ECONNABORTED) 492 continue; 493 exit(1); 494 } 495 memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero)); 496 if (setsockopt(msgsock, SOL_SOCKET, 497 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 498 syslog(LOG_ERR, 499 "setsockopt SO_KEEPALIVE: %m"); 500 nfsdargs.sock = msgsock; 501 nfsdargs.name = (caddr_t)&inetpeer; 502 nfsdargs.namelen = sizeof(inetpeer); 503 nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 504 (void)close(msgsock); 505 } 506 507 if (set[1].revents & POLLIN) { 508 len = sizeof(inet6peer); 509 if ((msgsock = accept(tcp6sock, 510 (struct sockaddr *)&inet6peer, &len)) < 0) { 511 serrno = errno; 512 syslog(LOG_ERR, "accept failed: %m"); 513 if (serrno == EINTR || serrno == ECONNABORTED) 514 continue; 515 exit(1); 516 } 517 if (setsockopt(msgsock, SOL_SOCKET, 518 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 519 syslog(LOG_ERR, 520 "setsockopt SO_KEEPALIVE: %m"); 521 nfsdargs.sock = msgsock; 522 nfsdargs.name = (caddr_t)&inet6peer; 523 nfsdargs.namelen = sizeof(inet6peer); 524 nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 525 (void)close(msgsock); 526 } 527 528 #ifdef notyet 529 if (set[2].revents & POLLIN) { 530 len = sizeof(isopeer); 531 if ((msgsock = accept(tp4sock, 532 (struct sockaddr *)&isopeer, &len)) < 0) { 533 serrno = errno; 534 syslog(LOG_ERR, "accept failed: %m"); 535 if (serrno == EINTR || serrno == ECONNABORTED) 536 continue; 537 exit(1); 538 } 539 if (setsockopt(msgsock, SOL_SOCKET, 540 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 541 syslog(LOG_ERR, 542 "setsockopt SO_KEEPALIVE: %m"); 543 nfsdargs.sock = msgsock; 544 nfsdargs.name = (caddr_t)&isopeer; 545 nfsdargs.namelen = len; 546 nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 547 (void)close(msgsock); 548 } 549 550 if (set[3].revents & POLLIN) { 551 len = sizeof(inetpeer); 552 if ((msgsock = accept(tpipsock, 553 (struct sockaddr *)&inetpeer, &len)) < 0) { 554 serrno = errno; 555 syslog(LOG_ERR, "accept failed: %m"); 556 if (serrno == EINTR || serrno == ECONNABORTED) 557 continue; 558 exit(1); 559 } 560 if (setsockopt(msgsock, SOL_SOCKET, 561 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) 562 syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m"); 563 nfsdargs.sock = msgsock; 564 nfsdargs.name = (caddr_t)&inetpeer; 565 nfsdargs.namelen = len; 566 nfssvc(NFSSVC_ADDSOCK, &nfsdargs); 567 (void)close(msgsock); 568 } 569 #endif /* notyet */ 570 } 571 } 572 573 void 574 usage() 575 { 576 (void)fprintf(stderr, "usage: nfsd %s\n", USAGE); 577 exit(1); 578 } 579 580 void 581 nonfs(signo) 582 int signo; 583 { 584 syslog(LOG_ERR, "missing system call: NFS not available."); 585 } 586