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