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