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