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