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