1 /* $OpenBSD: nfsd.c,v 1.36 2016/06/07 01:29:38 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 #include <sys/socketvar.h> 44 45 #include <rpc/rpc.h> 46 #include <rpc/pmap_clnt.h> 47 #include <rpc/pmap_prot.h> 48 49 #include <nfs/rpcv2.h> 50 #include <nfs/nfsproto.h> 51 #include <nfs/nfs.h> 52 53 #include <err.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <grp.h> 57 #include <pwd.h> 58 #include <signal.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <syslog.h> 63 #include <unistd.h> 64 65 /* Global defs */ 66 #ifdef DEBUG 67 #define syslog(e, s) fprintf(stderr,(s)) 68 int debug = 1; 69 #else 70 int debug = 0; 71 #endif 72 73 struct nfsd_srvargs nsd; 74 75 void nonfs(int); 76 void reapchild(int); 77 void usage(void); 78 79 #define MAXNFSDCNT 20 80 #define DEFNFSDCNT 4 81 82 /* 83 * Nfs server daemon mostly just a user context for nfssvc() 84 * 85 * 1 - do file descriptor and signal cleanup 86 * 2 - fork the nfsd(s) 87 * 3 - create server socket(s) 88 * 4 - register socket with portmap 89 * 90 * For connectionless protocols, just pass the socket into the kernel via. 91 * nfssvc(). 92 * For connection based sockets, loop doing accepts. When you get a new 93 * socket from accept, pass the msgsock into the kernel via. nfssvc(). 94 * The arguments are: 95 * -r - reregister with portmapper 96 * -t - support tcp nfs clients 97 * -u - support udp nfs clients 98 * followed by "n" which is the number of nfsds' to fork off 99 */ 100 int 101 main(int argc, char *argv[]) 102 { 103 struct nfsd_args nfsdargs; 104 struct sockaddr_in inetaddr; 105 int ch, connect_type_cnt, i; 106 int nfsdcnt = DEFNFSDCNT, on, reregister = 0, sock; 107 int udpflag = 0, tcpflag = 0, tcpsock; 108 const char *errstr = NULL; 109 110 /* Start by writing to both console and log. */ 111 openlog("nfsd", LOG_PID | LOG_PERROR, LOG_DAEMON); 112 113 if (argc == 1) 114 udpflag = 1; 115 while ((ch = getopt(argc, argv, "n:rtu")) != -1) 116 switch (ch) { 117 case 'n': 118 nfsdcnt = strtonum(optarg, 1, MAXNFSDCNT, &errstr); 119 if (errstr) { 120 syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg); 121 return(1); 122 } 123 break; 124 case 'r': 125 reregister = 1; 126 break; 127 case 't': 128 tcpflag = 1; 129 break; 130 case 'u': 131 udpflag = 1; 132 break; 133 default: 134 usage(); 135 }; 136 argv += optind; 137 argc -= optind; 138 139 /* 140 * XXX 141 * Backward compatibility, trailing number is the count of daemons. 142 */ 143 if (argc > 1) 144 usage(); 145 if (argc == 1) { 146 nfsdcnt = strtonum(argv[0], 1, MAXNFSDCNT, &errstr); 147 if (errstr) { 148 syslog(LOG_ERR, "nfsd count is %s: %s", errstr, optarg); 149 return(1); 150 } 151 } 152 153 if (debug == 0) { 154 daemon(0, 0); 155 (void)signal(SIGHUP, SIG_IGN); 156 (void)signal(SIGINT, SIG_IGN); 157 (void)signal(SIGQUIT, SIG_IGN); 158 (void)signal(SIGSYS, nonfs); 159 } 160 (void)signal(SIGCHLD, reapchild); 161 162 if (reregister) { 163 if (udpflag && 164 (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || 165 !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT))) { 166 syslog(LOG_ERR, "can't register with portmap for UDP (%m)."); 167 return (1); 168 } 169 if (tcpflag && 170 (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || 171 !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT))) { 172 syslog(LOG_ERR, "can't register with portmap for TCP (%m)."); 173 return (1); 174 } 175 return (0); 176 } 177 178 /* Cut back to writing to log only. */ 179 closelog(); 180 openlog("nfsd", LOG_PID, LOG_DAEMON); 181 182 for (i = 0; i < nfsdcnt; i++) { 183 switch (fork()) { 184 case -1: 185 syslog(LOG_ERR, "fork: %m"); 186 return (1); 187 case 0: 188 break; 189 default: 190 continue; 191 } 192 193 setproctitle("server"); 194 nsd.nsd_nfsd = NULL; 195 if (nfssvc(NFSSVC_NFSD, &nsd) < 0) { 196 syslog(LOG_ERR, "nfssvc: %m"); 197 return (1); 198 } 199 return (0); 200 } 201 202 /* If we are serving udp, set up the socket. */ 203 if (udpflag) { 204 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 205 syslog(LOG_ERR, "can't create udp socket"); 206 return (1); 207 } 208 memset(&inetaddr, 0, sizeof inetaddr); 209 inetaddr.sin_family = AF_INET; 210 inetaddr.sin_addr.s_addr = INADDR_ANY; 211 inetaddr.sin_port = htons(NFS_PORT); 212 inetaddr.sin_len = sizeof(inetaddr); 213 if (bind(sock, (struct sockaddr *)&inetaddr, 214 sizeof(inetaddr)) < 0) { 215 syslog(LOG_ERR, "can't bind udp addr"); 216 return (1); 217 } 218 if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_UDP, NFS_PORT) || 219 !pmap_set(RPCPROG_NFS, 3, IPPROTO_UDP, NFS_PORT)) { 220 syslog(LOG_ERR, "can't register with udp portmap"); 221 return (1); 222 } 223 nfsdargs.sock = sock; 224 nfsdargs.name = NULL; 225 nfsdargs.namelen = 0; 226 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { 227 syslog(LOG_ERR, "can't Add UDP socket"); 228 return (1); 229 } 230 (void)close(sock); 231 } 232 233 /* Now set up the master server socket waiting for tcp connections. */ 234 on = 1; 235 connect_type_cnt = 0; 236 if (tcpflag) { 237 if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 238 syslog(LOG_ERR, "can't create tcp socket"); 239 return (1); 240 } 241 if (setsockopt(tcpsock, 242 SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) 243 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); 244 memset(&inetaddr, 0, sizeof inetaddr); 245 inetaddr.sin_family = AF_INET; 246 inetaddr.sin_addr.s_addr = INADDR_ANY; 247 inetaddr.sin_port = htons(NFS_PORT); 248 inetaddr.sin_len = sizeof(inetaddr); 249 if (bind(tcpsock, (struct sockaddr *)&inetaddr, 250 sizeof (inetaddr)) < 0) { 251 syslog(LOG_ERR, "can't bind tcp addr"); 252 return (1); 253 } 254 if (listen(tcpsock, 5) < 0) { 255 syslog(LOG_ERR, "listen failed"); 256 return (1); 257 } 258 if (!pmap_set(RPCPROG_NFS, 2, IPPROTO_TCP, NFS_PORT) || 259 !pmap_set(RPCPROG_NFS, 3, IPPROTO_TCP, NFS_PORT)) { 260 syslog(LOG_ERR, "can't register tcp with portmap"); 261 return (1); 262 } 263 connect_type_cnt++; 264 } 265 266 if (connect_type_cnt == 0) 267 return (0); 268 269 setproctitle("master"); 270 271 /* 272 * Loop forever accepting connections and passing the sockets 273 * into the kernel for the mounts. 274 */ 275 for (;;) { 276 struct pollfd pfd; 277 struct sockaddr_in inetpeer; 278 int ret, msgsock; 279 socklen_t len; 280 281 pfd.fd = tcpsock; 282 pfd.events = POLLIN; 283 284 if (connect_type_cnt > 1) { 285 ret = poll(&pfd, 1, INFTIM); 286 if (ret < 1) { 287 syslog(LOG_ERR, "poll failed: %m"); 288 return (1); 289 } 290 291 } 292 293 if (tcpflag) { 294 len = sizeof(inetpeer); 295 if ((msgsock = accept(tcpsock, 296 (struct sockaddr *)&inetpeer, &len)) < 0) { 297 if (errno == EWOULDBLOCK || errno == EINTR || 298 errno == ECONNABORTED) 299 continue; 300 syslog(LOG_ERR, "accept failed: %m"); 301 return (1); 302 } 303 memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero)); 304 if (setsockopt(msgsock, SOL_SOCKET, 305 SO_KEEPALIVE, &on, sizeof(on)) < 0) 306 syslog(LOG_ERR, 307 "setsockopt SO_KEEPALIVE: %m"); 308 nfsdargs.sock = msgsock; 309 nfsdargs.name = (caddr_t)&inetpeer; 310 nfsdargs.namelen = sizeof(inetpeer); 311 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) { 312 syslog(LOG_ERR, "can't Add TCP socket"); 313 return (1); 314 } 315 (void)close(msgsock); 316 } 317 } 318 } 319 320 void 321 usage(void) 322 { 323 (void)fprintf(stderr, "usage: nfsd [-rtu] [-n num_servers]\n"); 324 exit(1); 325 } 326 327 /* ARGSUSED */ 328 void 329 nonfs(int signo) 330 { 331 int save_errno = errno; 332 struct syslog_data sdata = SYSLOG_DATA_INIT; 333 334 syslog_r(LOG_ERR, &sdata, "missing system call: NFS not available."); 335 errno = save_errno; 336 } 337 338 /* ARGSUSED */ 339 void 340 reapchild(int signo) 341 { 342 int save_errno = errno; 343 344 while (wait3(NULL, WNOHANG, NULL) > 0) 345 continue; 346 errno = save_errno; 347 } 348