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