1*c2a2da96Skn /* $OpenBSD: nfsd.c,v 1.45 2025/01/16 12:46:03 kn Exp $ */ 2be0fe854Sniklas /* $NetBSD: nfsd.c,v 1.19 1996/02/18 23:18:56 mycroft Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /* 5df930be7Sderaadt * Copyright (c) 1989, 1993, 1994 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * This code is derived from software contributed to Berkeley by 9df930be7Sderaadt * Rick Macklem at The University of Guelph. 10df930be7Sderaadt * 11df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 12df930be7Sderaadt * modification, are permitted provided that the following conditions 13df930be7Sderaadt * are met: 14df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 15df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 16df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 17df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 18df930be7Sderaadt * documentation and/or other materials provided with the distribution. 191ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors 20df930be7Sderaadt * may be used to endorse or promote products derived from this software 21df930be7Sderaadt * without specific prior written permission. 22df930be7Sderaadt * 23df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33df930be7Sderaadt * SUCH DAMAGE. 34df930be7Sderaadt */ 35df930be7Sderaadt 36df930be7Sderaadt #include <sys/ioctl.h> 37df930be7Sderaadt #include <sys/stat.h> 38df930be7Sderaadt #include <sys/wait.h> 39df930be7Sderaadt #include <sys/uio.h> 40df930be7Sderaadt #include <sys/ucred.h> 41df930be7Sderaadt #include <sys/mount.h> 42df930be7Sderaadt #include <sys/socket.h> 43df930be7Sderaadt 44df930be7Sderaadt #include <rpc/rpc.h> 45df930be7Sderaadt #include <rpc/pmap_clnt.h> 46df930be7Sderaadt #include <rpc/pmap_prot.h> 47df930be7Sderaadt 48df930be7Sderaadt #include <nfs/rpcv2.h> 49be0fe854Sniklas #include <nfs/nfsproto.h> 50df930be7Sderaadt #include <nfs/nfs.h> 51df930be7Sderaadt 52df930be7Sderaadt #include <err.h> 53df930be7Sderaadt #include <errno.h> 54df930be7Sderaadt #include <fcntl.h> 55df930be7Sderaadt #include <grp.h> 56df930be7Sderaadt #include <pwd.h> 57df930be7Sderaadt #include <signal.h> 58df930be7Sderaadt #include <stdio.h> 59df930be7Sderaadt #include <stdlib.h> 601d1da20fSmillert #include <string.h> 61be0fe854Sniklas #include <syslog.h> 62df930be7Sderaadt #include <unistd.h> 63df930be7Sderaadt 64df930be7Sderaadt /* Global defs */ 65df930be7Sderaadt #ifdef DEBUG 66c77ed605Smestre #define syslog(e, s, ...) \ 67c77ed605Smestre do { \ 68c77ed605Smestre fprintf(stderr, (s), ##__VA_ARGS__); \ 69c77ed605Smestre fprintf(stderr, "\n"); \ 70c77ed605Smestre } while (0) 71df930be7Sderaadt int debug = 1; 72df930be7Sderaadt #else 73df930be7Sderaadt int debug = 0; 74df930be7Sderaadt #endif 75df930be7Sderaadt 76df930be7Sderaadt struct nfsd_srvargs nsd; 77df930be7Sderaadt 78c72b5b24Smillert void nonfs(int); 79c72b5b24Smillert void reapchild(int); 80c72b5b24Smillert void usage(void); 81df930be7Sderaadt 821b85ea92Sderaadt #define MAXNFSDCNT 20 831b85ea92Sderaadt #define DEFNFSDCNT 4 841b85ea92Sderaadt 85df930be7Sderaadt /* 86df930be7Sderaadt * Nfs server daemon mostly just a user context for nfssvc() 87df930be7Sderaadt * 88df930be7Sderaadt * 1 - do file descriptor and signal cleanup 89df930be7Sderaadt * 2 - fork the nfsd(s) 90df930be7Sderaadt * 3 - create server socket(s) 91df930be7Sderaadt * 4 - register socket with portmap 92df930be7Sderaadt * 93df930be7Sderaadt * For connectionless protocols, just pass the socket into the kernel via. 94df930be7Sderaadt * nfssvc(). 95df930be7Sderaadt * For connection based sockets, loop doing accepts. When you get a new 96df930be7Sderaadt * socket from accept, pass the msgsock into the kernel via. nfssvc(). 97df930be7Sderaadt * The arguments are: 98df930be7Sderaadt * -r - reregister with portmapper 99df930be7Sderaadt * -t - support tcp nfs clients 100df930be7Sderaadt * -u - support udp nfs clients 101df930be7Sderaadt * followed by "n" which is the number of nfsds' to fork off 102df930be7Sderaadt */ 103df930be7Sderaadt int 104bc52e260Sderaadt main(int argc, char *argv[]) 105df930be7Sderaadt { 106df930be7Sderaadt struct nfsd_args nfsdargs; 107ec38e1feSchl struct sockaddr_in inetaddr; 1085ea00adcSkn int ch, i; 10909b20ce0Sthib int nfsdcnt = DEFNFSDCNT, on, reregister = 0, sock; 1101b85ea92Sderaadt int udpflag = 0, tcpflag = 0, tcpsock; 1111b85ea92Sderaadt const char *errstr = NULL; 112df930be7Sderaadt 1135dae5719Skrw /* Start by writing to both console and log. */ 1145dae5719Skrw openlog("nfsd", LOG_PID | LOG_PERROR, LOG_DAEMON); 1155dae5719Skrw 116*c2a2da96Skn if (unveil("/", "") == -1) { 117*c2a2da96Skn syslog(LOG_ERR, "unveil /: %s", strerror(errno)); 118*c2a2da96Skn return (1); 119*c2a2da96Skn } 120*c2a2da96Skn if (unveil(NULL, NULL) == -1) { 121*c2a2da96Skn syslog(LOG_ERR, "unveil: %s", strerror(errno)); 122*c2a2da96Skn return (1); 123*c2a2da96Skn } 124*c2a2da96Skn 1251b85ea92Sderaadt while ((ch = getopt(argc, argv, "n:rtu")) != -1) 126df930be7Sderaadt switch (ch) { 127df930be7Sderaadt case 'n': 1281b85ea92Sderaadt nfsdcnt = strtonum(optarg, 1, MAXNFSDCNT, &errstr); 1295dae5719Skrw if (errstr) { 1305dae5719Skrw syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg); 1315dae5719Skrw return(1); 1325dae5719Skrw } 133df930be7Sderaadt break; 134df930be7Sderaadt case 'r': 135df930be7Sderaadt reregister = 1; 136df930be7Sderaadt break; 137df930be7Sderaadt case 't': 138df930be7Sderaadt tcpflag = 1; 139df930be7Sderaadt break; 140df930be7Sderaadt case 'u': 141df930be7Sderaadt udpflag = 1; 142df930be7Sderaadt break; 143df930be7Sderaadt default: 144df930be7Sderaadt usage(); 145478f2fecStedu } 146df930be7Sderaadt argv += optind; 147df930be7Sderaadt argc -= optind; 148df930be7Sderaadt 1499a5c1bb0Skn if (!(tcpflag || udpflag)) 1509a5c1bb0Skn udpflag = 1; 1519a5c1bb0Skn 152df930be7Sderaadt /* 153df930be7Sderaadt * XXX 154df930be7Sderaadt * Backward compatibility, trailing number is the count of daemons. 155df930be7Sderaadt */ 156df930be7Sderaadt if (argc > 1) 157df930be7Sderaadt usage(); 158df930be7Sderaadt if (argc == 1) { 1591b85ea92Sderaadt nfsdcnt = strtonum(argv[0], 1, MAXNFSDCNT, &errstr); 1605dae5719Skrw if (errstr) { 1615dae5719Skrw syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg); 1625dae5719Skrw return(1); 1635dae5719Skrw } 164df930be7Sderaadt } 165df930be7Sderaadt 166df930be7Sderaadt if (debug == 0) { 167df930be7Sderaadt daemon(0, 0); 168df930be7Sderaadt (void)signal(SIGHUP, SIG_IGN); 169df930be7Sderaadt (void)signal(SIGINT, SIG_IGN); 170df930be7Sderaadt (void)signal(SIGQUIT, SIG_IGN); 171df930be7Sderaadt (void)signal(SIGSYS, nonfs); 172df930be7Sderaadt } 173df930be7Sderaadt (void)signal(SIGCHLD, reapchild); 174df930be7Sderaadt 175df930be7Sderaadt if (reregister) { 176df930be7Sderaadt if (udpflag && 177be0fe854Sniklas (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || 1785dae5719Skrw !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) { 179c77ed605Smestre syslog(LOG_ERR, "can't register with portmap for UDP (%s).", 180c77ed605Smestre strerror(errno)); 1815dae5719Skrw return (1); 1825dae5719Skrw } 183df930be7Sderaadt if (tcpflag && 184be0fe854Sniklas (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || 1855dae5719Skrw !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) { 186c77ed605Smestre syslog(LOG_ERR, "can't register with portmap for TCP (%s).", 187c77ed605Smestre strerror(errno)); 1885dae5719Skrw return (1); 1895dae5719Skrw } 19066420897Smickey return (0); 191df930be7Sderaadt } 1925dae5719Skrw 1935dae5719Skrw /* Cut back to writing to log only. */ 1945dae5719Skrw closelog(); 195ae9ae5acSderaadt openlog("nfsd", LOG_PID, LOG_DAEMON); 196df930be7Sderaadt 197df930be7Sderaadt for (i = 0; i < nfsdcnt; i++) { 198df930be7Sderaadt switch (fork()) { 199df930be7Sderaadt case -1: 200c77ed605Smestre syslog(LOG_ERR, "fork: %s", strerror(errno)); 20166420897Smickey return (1); 202df930be7Sderaadt case 0: 203df930be7Sderaadt break; 204df930be7Sderaadt default: 205df930be7Sderaadt continue; 206df930be7Sderaadt } 207df930be7Sderaadt 208df930be7Sderaadt setproctitle("server"); 209df930be7Sderaadt nsd.nsd_nfsd = NULL; 210df69c215Sderaadt if (nfssvc(NFSSVC_NFSD, &nsd) == -1) { 211c77ed605Smestre syslog(LOG_ERR, "nfssvc: %s", strerror(errno)); 21266420897Smickey return (1); 213df930be7Sderaadt } 21466420897Smickey return (0); 215df930be7Sderaadt } 216df930be7Sderaadt 217df930be7Sderaadt /* If we are serving udp, set up the socket. */ 218df930be7Sderaadt if (udpflag) { 219df69c215Sderaadt if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 220df930be7Sderaadt syslog(LOG_ERR, "can't create udp socket"); 22166420897Smickey return (1); 222df930be7Sderaadt } 22384b6bffdSderaadt memset(&inetaddr, 0, sizeof inetaddr); 224df930be7Sderaadt inetaddr.sin_family = AF_INET; 225df930be7Sderaadt inetaddr.sin_addr.s_addr = INADDR_ANY; 226df930be7Sderaadt inetaddr.sin_port = htons(NFS_PORT); 227df930be7Sderaadt inetaddr.sin_len = sizeof(inetaddr); 2281b85ea92Sderaadt if (bind(sock, (struct sockaddr *)&inetaddr, 229df69c215Sderaadt sizeof(inetaddr)) == -1) { 230df930be7Sderaadt syslog(LOG_ERR, "can't bind udp addr"); 23166420897Smickey return (1); 232df930be7Sderaadt } 233be0fe854Sniklas if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || 234be0fe854Sniklas !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) { 235df930be7Sderaadt syslog(LOG_ERR, "can't register with udp portmap"); 23666420897Smickey return (1); 237df930be7Sderaadt } 238df930be7Sderaadt nfsdargs.sock = sock; 239df930be7Sderaadt nfsdargs.name = NULL; 240df930be7Sderaadt nfsdargs.namelen = 0; 241df69c215Sderaadt if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) == -1) { 242df930be7Sderaadt syslog(LOG_ERR, "can't Add UDP socket"); 24366420897Smickey return (1); 244df930be7Sderaadt } 245df930be7Sderaadt (void)close(sock); 246df930be7Sderaadt } 247df930be7Sderaadt 248df930be7Sderaadt /* Now set up the master server socket waiting for tcp connections. */ 249df930be7Sderaadt on = 1; 2505ea00adcSkn if (!tcpflag) 2515ea00adcSkn return (0); 2525ea00adcSkn 253df69c215Sderaadt if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 254df930be7Sderaadt syslog(LOG_ERR, "can't create tcp socket"); 25566420897Smickey return (1); 256df930be7Sderaadt } 257df930be7Sderaadt if (setsockopt(tcpsock, 258df69c215Sderaadt SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) 259c77ed605Smestre syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %s", strerror(errno)); 26084b6bffdSderaadt memset(&inetaddr, 0, sizeof inetaddr); 261df930be7Sderaadt inetaddr.sin_family = AF_INET; 262df930be7Sderaadt inetaddr.sin_addr.s_addr = INADDR_ANY; 263df930be7Sderaadt inetaddr.sin_port = htons(NFS_PORT); 264df930be7Sderaadt inetaddr.sin_len = sizeof(inetaddr); 2651b85ea92Sderaadt if (bind(tcpsock, (struct sockaddr *)&inetaddr, 266df69c215Sderaadt sizeof (inetaddr)) == -1) { 267df930be7Sderaadt syslog(LOG_ERR, "can't bind tcp addr"); 26866420897Smickey return (1); 269df930be7Sderaadt } 270df69c215Sderaadt if (listen(tcpsock, 5) == -1) { 271df930be7Sderaadt syslog(LOG_ERR, "listen failed"); 27266420897Smickey return (1); 273df930be7Sderaadt } 274be0fe854Sniklas if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || 275be0fe854Sniklas !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) { 276df930be7Sderaadt syslog(LOG_ERR, "can't register tcp with portmap"); 27766420897Smickey return (1); 278df930be7Sderaadt } 279df930be7Sderaadt 280df930be7Sderaadt setproctitle("master"); 281df930be7Sderaadt 282df930be7Sderaadt /* 283df930be7Sderaadt * Loop forever accepting connections and passing the sockets 284df930be7Sderaadt * into the kernel for the mounts. 285df930be7Sderaadt */ 286df930be7Sderaadt for (;;) { 287df0b39aaStedu struct sockaddr_in inetpeer; 288df0b39aaStedu int ret, msgsock; 2895ea00adcSkn socklen_t len = sizeof(inetpeer); 290df0b39aaStedu 291df930be7Sderaadt if ((msgsock = accept(tcpsock, 292df69c215Sderaadt (struct sockaddr *)&inetpeer, &len)) == -1) { 29362e3c252Sderaadt if (errno == EWOULDBLOCK || errno == EINTR || 29462e3c252Sderaadt errno == ECONNABORTED) 29562e3c252Sderaadt continue; 296c77ed605Smestre syslog(LOG_ERR, "accept failed: %s", strerror(errno)); 29766420897Smickey return (1); 298df930be7Sderaadt } 299df930be7Sderaadt memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero)); 300df930be7Sderaadt if (setsockopt(msgsock, SOL_SOCKET, 301df69c215Sderaadt SO_KEEPALIVE, &on, sizeof(on)) == -1) 302df930be7Sderaadt syslog(LOG_ERR, 303c77ed605Smestre "setsockopt SO_KEEPALIVE: %s", strerror(errno)); 304df930be7Sderaadt nfsdargs.sock = msgsock; 305df930be7Sderaadt nfsdargs.name = (caddr_t)&inetpeer; 3065ea00adcSkn nfsdargs.namelen = len; 307df69c215Sderaadt if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) == -1) { 30809b20ce0Sthib syslog(LOG_ERR, "can't Add TCP socket"); 30909b20ce0Sthib } 310df930be7Sderaadt (void)close(msgsock); 311df930be7Sderaadt } 312df930be7Sderaadt } 313df930be7Sderaadt 314df930be7Sderaadt void 315bc52e260Sderaadt usage(void) 316df930be7Sderaadt { 3171b85ea92Sderaadt (void)fprintf(stderr, "usage: nfsd [-rtu] [-n num_servers]\n"); 318df930be7Sderaadt exit(1); 319df930be7Sderaadt } 320df930be7Sderaadt 321df930be7Sderaadt void 322bc52e260Sderaadt nonfs(int signo) 323df930be7Sderaadt { 324bc52e260Sderaadt int save_errno = errno; 325bc52e260Sderaadt struct syslog_data sdata = SYSLOG_DATA_INIT; 326bc52e260Sderaadt 327bc52e260Sderaadt syslog_r(LOG_ERR, &sdata, "missing system call: NFS not available."); 328bc52e260Sderaadt errno = save_errno; 329df930be7Sderaadt } 330df930be7Sderaadt 331df930be7Sderaadt void 332bc52e260Sderaadt reapchild(int signo) 333df930be7Sderaadt { 3346dccf94eSderaadt int save_errno = errno; 335df930be7Sderaadt 3366dccf94eSderaadt while (wait3(NULL, WNOHANG, NULL) > 0) 337252fb110Stedu continue; 3386dccf94eSderaadt errno = save_errno; 339df930be7Sderaadt } 340