1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 char copyright[] = 39 "@(#) Copyright (c) 1989 Regents of the University of California.\n\ 40 All rights reserved.\n"; 41 #endif not lint 42 43 #ifndef lint 44 /*static char sccsid[] = "from: @(#)nfsd.c 5.10 (Berkeley) 4/24/91";*/ 45 static char rcsid[] = "$Id: nfsd.c,v 1.7 1993/08/01 18:26:02 mycroft Exp $"; 46 #endif not lint 47 48 #include <sys/types.h> 49 #include <sys/signal.h> 50 #include <sys/ioctl.h> 51 #include <sys/stat.h> 52 #include <sys/wait.h> 53 #include <sys/mount.h> 54 #include <sys/socket.h> 55 #include <sys/socketvar.h> 56 #include <stdio.h> 57 #include <syslog.h> 58 #include <fcntl.h> 59 #include <string.h> 60 #include <netdb.h> 61 #include <rpc/rpc.h> 62 #include <rpc/pmap_clnt.h> 63 #include <rpc/pmap_prot.h> 64 #include <nfs/rpcv2.h> 65 #include <nfs/nfsv2.h> 66 #include <err.h> 67 68 #include <machine/vmparam.h> /* these are for PS_STRINGS */ 69 #include <sys/exec.h> 70 71 /* Global defs */ 72 #ifdef DEBUG 73 #define syslog(e, s) fprintf(stderr,(s)) 74 int debug = 1; 75 #else 76 int debug = 0; 77 #endif 78 struct hadr { 79 u_long ha_sad; 80 struct hadr *ha_next; 81 }; 82 struct hadr hphead; 83 char **Argv = NULL; /* pointer to argument vector */ 84 char *LastArg = NULL; /* end of argv */ 85 void reapchild(),not_nfsserver();; 86 87 /* 88 * Nfs server daemon mostly just a user context for nfssvc() 89 * 1 - do file descriptor and signal cleanup 90 * 2 - create server socket 91 * 3 - register socket with portmap 92 * For SOCK_DGRAM, just fork children and send them into the kernel 93 * by calling nfssvc() 94 * For connection based sockets, loop doing accepts. When you get a new socket 95 * from accept, fork a child that drops into the kernel via. nfssvc. 96 * This child will return from nfssvc when the connection is closed, so 97 * just shutdown() and exit(). 98 * The arguments are: 99 * -t - support tcp nfs clients 100 * -u - support udp nfs clients 101 */ 102 main(argc, argv, envp) 103 int argc; 104 char *argv[], *envp[]; 105 { 106 register int i; 107 register char *cp, *cp2; 108 register struct hadr *hp; 109 int udpcnt, sock, msgsock, tcpflag = 0, udpflag = 0, ret, len; 110 int reregister = 0; 111 char opt; 112 extern int optind; 113 extern char *optarg; 114 struct sockaddr_in saddr, msk, mtch, peername; 115 116 117 /* 118 * Save start and extent of argv for setproctitle. 119 */ 120 121 Argv = argv; 122 if (envp == 0 || *envp == 0) 123 envp = argv; 124 while (*envp) 125 envp++; 126 LastArg = envp[-1] + strlen(envp[-1]); 127 while ((opt = getopt(argc, argv, "rt:u:")) != EOF) 128 switch (opt) { 129 case 'r': 130 reregister++; 131 break; 132 case 't': 133 tcpflag++; 134 if (cp = index(optarg, ',')) { 135 *cp++ = '\0'; 136 msk.sin_addr.s_addr = inet_addr(optarg); 137 if (msk.sin_addr.s_addr == -1) 138 usage(); 139 if (cp2 = index(cp, ',')) 140 *cp2++ = '\0'; 141 mtch.sin_addr.s_addr = inet_addr(cp); 142 if (mtch.sin_addr.s_addr == -1) 143 usage(); 144 cp = cp2; 145 hphead.ha_next = (struct hadr *)0; 146 while (cp) { 147 if (cp2 = index(cp, ',')) 148 *cp2++ = '\0'; 149 hp = (struct hadr *) 150 malloc(sizeof (struct hadr)); 151 hp->ha_sad = inet_addr(cp); 152 if (hp->ha_sad == -1) 153 usage(); 154 hp->ha_next = hphead.ha_next; 155 hphead.ha_next = hp; 156 cp = cp2; 157 } 158 } else 159 usage(); 160 break; 161 case 'u': 162 udpflag++; 163 if (cp = index(optarg, ',')) { 164 *cp++ = '\0'; 165 msk.sin_addr.s_addr = inet_addr(optarg); 166 if (msk.sin_addr.s_addr == -1) 167 usage(); 168 if (cp2 = index(cp, ',')) 169 *cp2++ = '\0'; 170 mtch.sin_addr.s_addr = inet_addr(cp); 171 if (mtch.sin_addr.s_addr == -1) 172 usage(); 173 if (cp2) 174 udpcnt = atoi(cp2); 175 if (udpcnt < 1 || udpcnt > 20) 176 udpcnt = 1; 177 } else 178 usage(); 179 break; 180 default: 181 case '?': 182 usage(); 183 } 184 185 /* 186 * Default, if neither UDP nor TCP is specified, 187 * is to support UDP only; a numeric argument indicates 188 * the number of server daemons to run. 189 */ 190 if (udpflag == 0 && tcpflag == 0) { 191 if (argc > 1) 192 udpcnt = atoi(*++argv); 193 if (udpcnt < 1 || udpcnt > 20) 194 udpcnt = 1; 195 msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0; 196 udpflag++; 197 } 198 199 if (debug == 0) { 200 daemon(0, 0); 201 signal(SIGINT, SIG_IGN); 202 signal(SIGQUIT, SIG_IGN); 203 signal(SIGTERM, SIG_IGN); 204 signal(SIGHUP, SIG_IGN); 205 } 206 signal(SIGCHLD, reapchild); 207 signal(SIGSYS, not_nfsserver); 208 if (nfssvc(-1, NULL, 0, NULL, 0) >= 0) 209 err(1, "bad arguments didn't cause error"); 210 if (reregister) { 211 if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, 212 NFS_PORT)) { 213 fprintf(stderr, 214 "Can't register with portmap for UDP\n"); 215 exit(1); 216 } 217 if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, 218 NFS_PORT)) { 219 fprintf(stderr, 220 "Can't register with portmap for TCP\n"); 221 exit(1); 222 } 223 exit(0); 224 } 225 openlog("nfsd:", LOG_PID, LOG_DAEMON); 226 #ifdef notdef 227 /* why? unregisters both protocols even if we restart only one */ 228 pmap_unset(RPCPROG_NFS, NFS_VER2); 229 #endif 230 if (udpflag) { 231 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 232 syslog(LOG_ERR, "Can't create socket"); 233 exit(1); 234 } 235 saddr.sin_family = AF_INET; 236 saddr.sin_addr.s_addr = INADDR_ANY; 237 saddr.sin_port = htons(NFS_PORT); 238 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 239 syslog(LOG_ERR, "Can't bind addr"); 240 exit(1); 241 } 242 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) { 243 syslog(LOG_ERR, "Can't register with portmap"); 244 exit(1); 245 } 246 247 /* 248 * Send the nfs datagram servers 249 * right down into the kernel 250 */ 251 for (i = 0; i < udpcnt; i++) 252 if (fork() == 0) { 253 setproctitle("nfsd-udp", 254 (struct sockaddr_in *)NULL); 255 ret = nfssvc(sock, &msk, sizeof(msk), 256 &mtch, sizeof(mtch)); 257 if (ret < 0) 258 syslog(LOG_ERR, "nfssvc() failed %m"); 259 exit(1); 260 } 261 close(sock); 262 } 263 264 /* 265 * Now set up the master STREAM server waiting for tcp connections. 266 */ 267 if (tcpflag) { 268 int on = 1; 269 270 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 271 syslog(LOG_ERR, "Can't create socket"); 272 exit(1); 273 } 274 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 275 (char *) &on, sizeof(on)) < 0) 276 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); 277 saddr.sin_family = AF_INET; 278 saddr.sin_addr.s_addr = INADDR_ANY; 279 saddr.sin_port = htons(NFS_PORT); 280 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 281 syslog(LOG_ERR, "Can't bind addr"); 282 exit(1); 283 } 284 if (listen(sock, 5) < 0) { 285 syslog(LOG_ERR, "Listen failed"); 286 exit(1); 287 } 288 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) { 289 syslog(LOG_ERR, "Can't register with portmap"); 290 exit(1); 291 } 292 setproctitle("nfsd-listen", (struct sockaddr_in *)NULL); 293 /* 294 * Loop forever accepting connections and sending the children 295 * into the kernel to service the mounts. 296 */ 297 for (;;) { 298 len = sizeof(peername); 299 if ((msgsock = accept(sock, 300 (struct sockaddr *)&peername, &len)) < 0) { 301 syslog(LOG_ERR, "Accept failed: %m"); 302 exit(1); 303 } 304 if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr) != 305 mtch.sin_addr.s_addr) { 306 hp = hphead.ha_next; 307 while (hp) { 308 if (peername.sin_addr.s_addr == 309 hp->ha_sad) 310 break; 311 hp = hp->ha_next; 312 } 313 if (hp == NULL) { 314 shutdown(msgsock, 2); 315 close(msgsock); 316 continue; 317 } 318 } 319 if (fork() == 0) { 320 close(sock); 321 setproctitle("nfsd-tcp", &peername); 322 if (setsockopt(msgsock, SOL_SOCKET, 323 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) 324 syslog(LOG_ERR, 325 "setsockopt SO_KEEPALIVE: %m"); 326 ret = nfssvc(msgsock, &msk, sizeof(msk), 327 &mtch, sizeof(mtch)); 328 shutdown(msgsock, 2); 329 if (ret < 0) 330 syslog(LOG_NOTICE, 331 "Nfssvc STREAM Failed"); 332 exit(1); 333 } 334 close(msgsock); 335 } 336 } 337 } 338 339 usage() 340 { 341 fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n"); 342 exit(1); 343 } 344 345 void 346 reapchild() 347 { 348 349 while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL)) 350 ; 351 } 352 353 setproctitle(a, sin) 354 char *a; 355 struct sockaddr_in *sin; 356 { 357 register char *cp; 358 static char buf[80]; 359 360 if (sin) 361 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin->sin_addr)); 362 else 363 (void) sprintf(buf, "%s", a); 364 PS_STRINGS->ps_nargvstr = 1; 365 PS_STRINGS->ps_argvstr = buf; 366 } 367 368 void not_nfsserver() 369 { 370 err(1, "not configured as NFS server\n"); 371 } 372