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.8 1993/10/05 00:36:28 cgd 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 67 #include <machine/vmparam.h> /* these are for PS_STRINGS */ 68 #include <sys/exec.h> 69 70 /* Global defs */ 71 #ifdef DEBUG 72 #define syslog(e, s) fprintf(stderr,(s)) 73 int debug = 1; 74 #else 75 int debug = 0; 76 #endif 77 struct hadr { 78 u_long ha_sad; 79 struct hadr *ha_next; 80 }; 81 struct hadr hphead; 82 char **Argv = NULL; /* pointer to argument vector */ 83 char *LastArg = NULL; /* end of argv */ 84 void reapchild(),not_nfsserver();; 85 86 /* 87 * Nfs server daemon mostly just a user context for nfssvc() 88 * 1 - do file descriptor and signal cleanup 89 * 2 - create server socket 90 * 3 - register socket with portmap 91 * For SOCK_DGRAM, just fork children and send them into the kernel 92 * by calling nfssvc() 93 * For connection based sockets, loop doing accepts. When you get a new socket 94 * from accept, fork a child that drops into the kernel via. nfssvc. 95 * This child will return from nfssvc when the connection is closed, so 96 * just shutdown() and exit(). 97 * The arguments are: 98 * -t - support tcp nfs clients 99 * -u - support udp nfs clients 100 */ 101 main(argc, argv, envp) 102 int argc; 103 char *argv[], *envp[]; 104 { 105 register int i; 106 register char *cp, *cp2; 107 register struct hadr *hp; 108 int udpcnt, sock, msgsock, tcpflag = 0, udpflag = 0, ret, len; 109 int reregister = 0; 110 char opt; 111 extern int optind; 112 extern char *optarg; 113 struct sockaddr_in saddr, msk, mtch, peername; 114 115 116 /* 117 * Save start and extent of argv for setproctitle. 118 */ 119 120 Argv = argv; 121 if (envp == 0 || *envp == 0) 122 envp = argv; 123 while (*envp) 124 envp++; 125 LastArg = envp[-1] + strlen(envp[-1]); 126 while ((opt = getopt(argc, argv, "rt:u:")) != EOF) 127 switch (opt) { 128 case 'r': 129 reregister++; 130 break; 131 case 't': 132 tcpflag++; 133 if (cp = index(optarg, ',')) { 134 *cp++ = '\0'; 135 msk.sin_addr.s_addr = inet_addr(optarg); 136 if (msk.sin_addr.s_addr == -1) 137 usage(); 138 if (cp2 = index(cp, ',')) 139 *cp2++ = '\0'; 140 mtch.sin_addr.s_addr = inet_addr(cp); 141 if (mtch.sin_addr.s_addr == -1) 142 usage(); 143 cp = cp2; 144 hphead.ha_next = (struct hadr *)0; 145 while (cp) { 146 if (cp2 = index(cp, ',')) 147 *cp2++ = '\0'; 148 hp = (struct hadr *) 149 malloc(sizeof (struct hadr)); 150 hp->ha_sad = inet_addr(cp); 151 if (hp->ha_sad == -1) 152 usage(); 153 hp->ha_next = hphead.ha_next; 154 hphead.ha_next = hp; 155 cp = cp2; 156 } 157 } else 158 usage(); 159 break; 160 case 'u': 161 udpflag++; 162 if (cp = index(optarg, ',')) { 163 *cp++ = '\0'; 164 msk.sin_addr.s_addr = inet_addr(optarg); 165 if (msk.sin_addr.s_addr == -1) 166 usage(); 167 if (cp2 = index(cp, ',')) 168 *cp2++ = '\0'; 169 mtch.sin_addr.s_addr = inet_addr(cp); 170 if (mtch.sin_addr.s_addr == -1) 171 usage(); 172 if (cp2) 173 udpcnt = atoi(cp2); 174 if (udpcnt < 1 || udpcnt > 20) 175 udpcnt = 1; 176 } else 177 usage(); 178 break; 179 default: 180 case '?': 181 usage(); 182 } 183 184 /* 185 * Default, if neither UDP nor TCP is specified, 186 * is to support UDP only; a numeric argument indicates 187 * the number of server daemons to run. 188 */ 189 if (udpflag == 0 && tcpflag == 0) { 190 if (argc > 1) 191 udpcnt = atoi(*++argv); 192 if (udpcnt < 1 || udpcnt > 20) 193 udpcnt = 1; 194 msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0; 195 udpflag++; 196 } 197 198 if (debug == 0) { 199 daemon(0, 0); 200 signal(SIGINT, SIG_IGN); 201 signal(SIGQUIT, SIG_IGN); 202 signal(SIGTERM, SIG_IGN); 203 signal(SIGHUP, SIG_IGN); 204 } 205 signal(SIGCHLD, reapchild); 206 signal(SIGSYS, not_nfsserver); 207 if (nfssvc(-1, NULL, 0, NULL, 0) >= 0) { 208 syslog(LOG_ERR, "bad arguments didn't cause error"); 209 exit(1); 210 } 211 if (reregister) { 212 if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, 213 NFS_PORT)) { 214 fprintf(stderr, 215 "Can't register with portmap for UDP\n"); 216 exit(1); 217 } 218 if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, 219 NFS_PORT)) { 220 fprintf(stderr, 221 "Can't register with portmap for TCP\n"); 222 exit(1); 223 } 224 exit(0); 225 } 226 openlog("nfsd:", LOG_PID, LOG_DAEMON); 227 #ifdef notdef 228 /* why? unregisters both protocols even if we restart only one */ 229 pmap_unset(RPCPROG_NFS, NFS_VER2); 230 #endif 231 if (udpflag) { 232 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 233 syslog(LOG_ERR, "Can't create socket"); 234 exit(1); 235 } 236 saddr.sin_family = AF_INET; 237 saddr.sin_addr.s_addr = INADDR_ANY; 238 saddr.sin_port = htons(NFS_PORT); 239 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 240 syslog(LOG_ERR, "Can't bind addr"); 241 exit(1); 242 } 243 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) { 244 syslog(LOG_ERR, "Can't register with portmap"); 245 exit(1); 246 } 247 248 /* 249 * Send the nfs datagram servers 250 * right down into the kernel 251 */ 252 for (i = 0; i < udpcnt; i++) 253 if (fork() == 0) { 254 setproctitle("nfsd-udp", 255 (struct sockaddr_in *)NULL); 256 ret = nfssvc(sock, &msk, sizeof(msk), 257 &mtch, sizeof(mtch)); 258 if (ret < 0) 259 syslog(LOG_ERR, "nfssvc() failed %m"); 260 exit(1); 261 } 262 close(sock); 263 } 264 265 /* 266 * Now set up the master STREAM server waiting for tcp connections. 267 */ 268 if (tcpflag) { 269 int on = 1; 270 271 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { 272 syslog(LOG_ERR, "Can't create socket"); 273 exit(1); 274 } 275 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 276 (char *) &on, sizeof(on)) < 0) 277 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); 278 saddr.sin_family = AF_INET; 279 saddr.sin_addr.s_addr = INADDR_ANY; 280 saddr.sin_port = htons(NFS_PORT); 281 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) { 282 syslog(LOG_ERR, "Can't bind addr"); 283 exit(1); 284 } 285 if (listen(sock, 5) < 0) { 286 syslog(LOG_ERR, "Listen failed"); 287 exit(1); 288 } 289 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) { 290 syslog(LOG_ERR, "Can't register with portmap"); 291 exit(1); 292 } 293 setproctitle("nfsd-listen", (struct sockaddr_in *)NULL); 294 /* 295 * Loop forever accepting connections and sending the children 296 * into the kernel to service the mounts. 297 */ 298 for (;;) { 299 len = sizeof(peername); 300 if ((msgsock = accept(sock, 301 (struct sockaddr *)&peername, &len)) < 0) { 302 syslog(LOG_ERR, "Accept failed: %m"); 303 exit(1); 304 } 305 if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr) != 306 mtch.sin_addr.s_addr) { 307 hp = hphead.ha_next; 308 while (hp) { 309 if (peername.sin_addr.s_addr == 310 hp->ha_sad) 311 break; 312 hp = hp->ha_next; 313 } 314 if (hp == NULL) { 315 shutdown(msgsock, 2); 316 close(msgsock); 317 continue; 318 } 319 } 320 if (fork() == 0) { 321 close(sock); 322 setproctitle("nfsd-tcp", &peername); 323 if (setsockopt(msgsock, SOL_SOCKET, 324 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) 325 syslog(LOG_ERR, 326 "setsockopt SO_KEEPALIVE: %m"); 327 ret = nfssvc(msgsock, &msk, sizeof(msk), 328 &mtch, sizeof(mtch)); 329 shutdown(msgsock, 2); 330 if (ret < 0) 331 syslog(LOG_NOTICE, 332 "Nfssvc STREAM Failed"); 333 exit(1); 334 } 335 close(msgsock); 336 } 337 } 338 } 339 340 usage() 341 { 342 fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n"); 343 exit(1); 344 } 345 346 void 347 reapchild() 348 { 349 350 while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL)) 351 ; 352 } 353 354 setproctitle(a, sin) 355 char *a; 356 struct sockaddr_in *sin; 357 { 358 register char *cp; 359 static char buf[80]; 360 361 if (sin) 362 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin->sin_addr)); 363 else 364 (void) sprintf(buf, "%s", a); 365 PS_STRINGS->ps_nargvstr = 1; 366 PS_STRINGS->ps_argvstr = buf; 367 } 368 369 void not_nfsserver() 370 { 371 syslog(LOG_ERR, "not configured as NFS server"); 372 exit(1); 373 } 374