1 /* $OpenBSD: nfsd.c,v 1.40 2020/01/22 06:24:08 tedu Exp $ */ 2 /* $NetBSD: nfsd.c,v 1.19 1996/02/18 23:18:56 mycroft Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Rick Macklem at The University of Guelph. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/ioctl.h> 37 #include <sys/stat.h> 38 #include <sys/wait.h> 39 #include <sys/uio.h> 40 #include <sys/ucred.h> 41 #include <sys/mount.h> 42 #include <sys/socket.h> 43 44 #include <rpc/rpc.h> 45 #include <rpc/pmap_clnt.h> 46 #include <rpc/pmap_prot.h> 47 48 #include <nfs/rpcv2.h> 49 #include <nfs/nfsproto.h> 50 #include <nfs/nfs.h> 51 52 #include <err.h> 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <grp.h> 56 #include <pwd.h> 57 #include <signal.h> 58 #include <stdio.h> 59 #include <stdlib.h> 60 #include <string.h> 61 #include <syslog.h> 62 #include <unistd.h> 63 64 /* Global defs */ 65 #ifdef DEBUG 66 #define syslog(e, s, ...) \ 67 do { \ 68 fprintf(stderr, (s), ##__VA_ARGS__); \ 69 fprintf(stderr, "\n"); \ 70 } while (0) 71 int debug = 1; 72 #else 73 int debug = 0; 74 #endif 75 76 struct nfsd_srvargs nsd; 77 78 void nonfs(int); 79 void reapchild(int); 80 void usage(void); 81 82 #define MAXNFSDCNT 20 83 #define DEFNFSDCNT 4 84 85 /* 86 * Nfs server daemon mostly just a user context for nfssvc() 87 * 88 * 1 - do file descriptor and signal cleanup 89 * 2 - fork the nfsd(s) 90 * 3 - create server socket(s) 91 * 4 - register socket with portmap 92 * 93 * For connectionless protocols, just pass the socket into the kernel via. 94 * nfssvc(). 95 * For connection based sockets, loop doing accepts. When you get a new 96 * socket from accept, pass the msgsock into the kernel via. nfssvc(). 97 * The arguments are: 98 * -r - reregister with portmapper 99 * -t - support tcp nfs clients 100 * -u - support udp nfs clients 101 * followed by "n" which is the number of nfsds' to fork off 102 */ 103 int 104 main(int argc, char *argv[]) 105 { 106 struct nfsd_args nfsdargs; 107 struct sockaddr_in inetaddr; 108 int ch, connect_type_cnt, i; 109 int nfsdcnt = DEFNFSDCNT, on, reregister = 0, sock; 110 int udpflag = 0, tcpflag = 0, tcpsock; 111 const char *errstr = NULL; 112 113 /* Start by writing to both console and log. */ 114 openlog("nfsd", LOG_PID | LOG_PERROR, LOG_DAEMON); 115 116 if (argc == 1) 117 udpflag = 1; 118 while ((ch = getopt(argc, argv, "n:rtu")) != -1) 119 switch (ch) { 120 case 'n': 121 nfsdcnt = strtonum(optarg, 1, MAXNFSDCNT, &errstr); 122 if (errstr) { 123 syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg); 124 return(1); 125 } 126 break; 127 case 'r': 128 reregister = 1; 129 break; 130 case 't': 131 tcpflag = 1; 132 break; 133 case 'u': 134 udpflag = 1; 135 break; 136 default: 137 usage(); 138 } 139 argv += optind; 140 argc -= optind; 141 142 /* 143 * XXX 144 * Backward compatibility, trailing number is the count of daemons. 145 */ 146 if (argc > 1) 147 usage(); 148 if (argc == 1) { 149 nfsdcnt = strtonum(argv[0], 1, MAXNFSDCNT, &errstr); 150 if (errstr) { 151 syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg); 152 return(1); 153 } 154 } 155 156 if (debug == 0) { 157 daemon(0, 0); 158 (void)signal(SIGHUP, SIG_IGN); 159 (void)signal(SIGINT, SIG_IGN); 160 (void)signal(SIGQUIT, SIG_IGN); 161 (void)signal(SIGSYS, nonfs); 162 } 163 (void)signal(SIGCHLD, reapchild); 164 165 if (reregister) { 166 if (udpflag && 167 (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || 168 !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) { 169 syslog(LOG_ERR, "can't register with portmap for UDP (%s).", 170 strerror(errno)); 171 return (1); 172 } 173 if (tcpflag && 174 (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || 175 !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) { 176 syslog(LOG_ERR, "can't register with portmap for TCP (%s).", 177 strerror(errno)); 178 return (1); 179 } 180 return (0); 181 } 182 183 /* Cut back to writing to log only. */ 184 closelog(); 185 openlog("nfsd", LOG_PID, LOG_DAEMON); 186 187 for (i = 0; i < nfsdcnt; i++) { 188 switch (fork()) { 189 case -1: 190 syslog(LOG_ERR, "fork: %s", strerror(errno)); 191 return (1); 192 case 0: 193 break; 194 default: 195 continue; 196 } 197 198 setproctitle("server"); 199 nsd.nsd_nfsd = NULL; 200 if (nfssvc(NFSSVC_NFSD, &nsd) == -1) { 201 syslog(LOG_ERR, "nfssvc: %s", strerror(errno)); 202 return (1); 203 } 204 return (0); 205 } 206 207 /* If we are serving udp, set up the socket. */ 208 if (udpflag) { 209 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { 210 syslog(LOG_ERR, "can't create udp socket"); 211 return (1); 212 } 213 memset(&inetaddr, 0, sizeof inetaddr); 214 inetaddr.sin_family = AF_INET; 215 inetaddr.sin_addr.s_addr = INADDR_ANY; 216 inetaddr.sin_port = htons(NFS_PORT); 217 inetaddr.sin_len = sizeof(inetaddr); 218 if (bind(sock, (struct sockaddr *)&inetaddr, 219 sizeof(inetaddr)) == -1) { 220 syslog(LOG_ERR, "can't bind udp addr"); 221 return (1); 222 } 223 if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || 224 !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) { 225 syslog(LOG_ERR, "can't register with udp portmap"); 226 return (1); 227 } 228 nfsdargs.sock = sock; 229 nfsdargs.name = NULL; 230 nfsdargs.namelen = 0; 231 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) == -1) { 232 syslog(LOG_ERR, "can't Add UDP socket"); 233 return (1); 234 } 235 (void)close(sock); 236 } 237 238 /* Now set up the master server socket waiting for tcp connections. */ 239 on = 1; 240 connect_type_cnt = 0; 241 if (tcpflag) { 242 if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { 243 syslog(LOG_ERR, "can't create tcp socket"); 244 return (1); 245 } 246 if (setsockopt(tcpsock, 247 SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) 248 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %s", strerror(errno)); 249 memset(&inetaddr, 0, sizeof inetaddr); 250 inetaddr.sin_family = AF_INET; 251 inetaddr.sin_addr.s_addr = INADDR_ANY; 252 inetaddr.sin_port = htons(NFS_PORT); 253 inetaddr.sin_len = sizeof(inetaddr); 254 if (bind(tcpsock, (struct sockaddr *)&inetaddr, 255 sizeof (inetaddr)) == -1) { 256 syslog(LOG_ERR, "can't bind tcp addr"); 257 return (1); 258 } 259 if (listen(tcpsock, 5) == -1) { 260 syslog(LOG_ERR, "listen failed"); 261 return (1); 262 } 263 if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || 264 !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) { 265 syslog(LOG_ERR, "can't register tcp with portmap"); 266 return (1); 267 } 268 connect_type_cnt++; 269 } 270 271 if (connect_type_cnt == 0) 272 return (0); 273 274 setproctitle("master"); 275 276 /* 277 * Loop forever accepting connections and passing the sockets 278 * into the kernel for the mounts. 279 */ 280 for (;;) { 281 struct pollfd pfd; 282 struct sockaddr_in inetpeer; 283 int ret, msgsock; 284 socklen_t len; 285 286 pfd.fd = tcpsock; 287 pfd.events = POLLIN; 288 289 if (connect_type_cnt > 1) { 290 ret = poll(&pfd, 1, INFTIM); 291 if (ret < 1) { 292 syslog(LOG_ERR, "poll failed: %s", strerror(errno)); 293 return (1); 294 } 295 296 } 297 298 if (tcpflag) { 299 len = sizeof(inetpeer); 300 if ((msgsock = accept(tcpsock, 301 (struct sockaddr *)&inetpeer, &len)) == -1) { 302 if (errno == EWOULDBLOCK || errno == EINTR || 303 errno == ECONNABORTED) 304 continue; 305 syslog(LOG_ERR, "accept failed: %s", strerror(errno)); 306 return (1); 307 } 308 memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero)); 309 if (setsockopt(msgsock, SOL_SOCKET, 310 SO_KEEPALIVE, &on, sizeof(on)) == -1) 311 syslog(LOG_ERR, 312 "setsockopt SO_KEEPALIVE: %s", strerror(errno)); 313 nfsdargs.sock = msgsock; 314 nfsdargs.name = (caddr_t)&inetpeer; 315 nfsdargs.namelen = sizeof(inetpeer); 316 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) == -1) { 317 syslog(LOG_ERR, "can't Add TCP socket"); 318 return (1); 319 } 320 (void)close(msgsock); 321 } 322 } 323 } 324 325 void 326 usage(void) 327 { 328 (void)fprintf(stderr, "usage: nfsd [-rtu] [-n num_servers]\n"); 329 exit(1); 330 } 331 332 /* ARGSUSED */ 333 void 334 nonfs(int signo) 335 { 336 int save_errno = errno; 337 struct syslog_data sdata = SYSLOG_DATA_INIT; 338 339 syslog_r(LOG_ERR, &sdata, "missing system call: NFS not available."); 340 errno = save_errno; 341 } 342 343 /* ARGSUSED */ 344 void 345 reapchild(int signo) 346 { 347 int save_errno = errno; 348 349 while (wait3(NULL, WNOHANG, NULL) > 0) 350 continue; 351 errno = save_errno; 352 } 353