xref: /original-bsd/sbin/nfsd/nfsd.c (revision 72b8f354)
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  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif not lint
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)nfsd.c	5.8 (Berkeley) 06/29/90";
19 #endif not lint
20 
21 #include <sys/types.h>
22 #include <sys/signal.h>
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25 #include <sys/wait.h>
26 #include <sys/mount.h>
27 #include <sys/socket.h>
28 #include <sys/socketvar.h>
29 #include <stdio.h>
30 #include <syslog.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <netdb.h>
34 #include <rpc/rpc.h>
35 #include <rpc/pmap_clnt.h>
36 #include <rpc/pmap_prot.h>
37 #include <nfs/rpcv2.h>
38 #include <nfs/nfsv2.h>
39 
40 /* Global defs */
41 #ifdef DEBUG
42 #define	syslog(e, s)	fprintf(stderr,(s))
43 int debug = 1;
44 #else
45 int debug = 0;
46 #endif
47 struct hadr {
48 	u_long	ha_sad;
49 	struct hadr *ha_next;
50 };
51 struct hadr hphead;
52 
53 /*
54  * Nfs server daemon mostly just a user context for nfssvc()
55  * 1 - do file descriptor and signal cleanup
56  * 2 - create server socket
57  * 3 - register socket with portmap
58  * For SOCK_DGRAM, just fork children and send them into the kernel
59  * by calling nfssvc()
60  * For connection based sockets, loop doing accepts. When you get a new socket
61  * from accept, fork a child that drops into the kernel via. nfssvc.
62  * This child will return from nfssvc when the connection is closed, so
63  * just shutdown() and exit().
64  * The arguments are:
65  * -t - support tcp nfs clients
66  * -u - support udp nfs clients
67  */
68 main(argc, argv)
69 	int argc;
70 	char **argv;
71 {
72 	register int i;
73 	register char *cp, *cp2;
74 	register struct hadr *hp;
75 	int udpcnt, sock, msgsock, tcpflag = 0, udpflag = 0, ret, len;
76 	char opt;
77 	union wait chldstat;
78 	extern int optind;
79 	extern char *optarg;
80 	struct sockaddr_in saddr, msk, mtch, peername;
81 
82 	while ((opt = getopt(argc, argv, "t:u:")) != EOF)
83 		switch (opt) {
84 		case 't':
85 			tcpflag++;
86 			if (cp = index(optarg, ',')) {
87 				*cp++ = '\0';
88 				msk.sin_addr.s_addr = inet_addr(optarg);
89 				if (msk.sin_addr.s_addr == -1)
90 					usage();
91 				if (cp2 = index(cp, ','))
92 					*cp2++ = '\0';
93 				mtch.sin_addr.s_addr = inet_addr(cp);
94 				if (mtch.sin_addr.s_addr == -1)
95 					usage();
96 				cp = cp2;
97 				hphead.ha_next = (struct hadr *)0;
98 				while (cp) {
99 					if (cp2 = index(cp, ','))
100 						*cp2++ = '\0';
101 					hp = (struct hadr *)
102 						malloc(sizeof (struct hadr));
103 					hp->ha_sad = inet_addr(cp);
104 					if (hp->ha_sad == -1)
105 						usage();
106 					hp->ha_next = hphead.ha_next;
107 					hphead.ha_next = hp;
108 					cp = cp2;
109 				}
110 			} else
111 				usage();
112 			break;
113 		case 'u':
114 			udpflag++;
115 			if (cp = index(optarg, ',')) {
116 				*cp++ = '\0';
117 				msk.sin_addr.s_addr = inet_addr(optarg);
118 				if (msk.sin_addr.s_addr == -1)
119 					usage();
120 				if (cp2 = index(cp, ','))
121 					*cp2++ = '\0';
122 				mtch.sin_addr.s_addr = inet_addr(cp);
123 				if (mtch.sin_addr.s_addr == -1)
124 					usage();
125 				if (cp2)
126 					udpcnt = atoi(cp2);
127 				if (udpcnt < 1 || udpcnt > 20)
128 					udpcnt = 1;
129 			} else
130 				usage();
131 			break;
132 		default:
133 		case '?':
134 			usage();
135 		};
136 	if (optind == 1) {
137 		if (argc > 1)
138 			udpcnt = atoi(*++argv);
139 		if (udpcnt < 1 || udpcnt > 20)
140 			udpcnt = 1;
141 		msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0;
142 		udpflag++;
143 	}
144 	if (debug == 0) {
145 		daemon(0, 0);
146 		signal(SIGINT, SIG_IGN);
147 		signal(SIGQUIT, SIG_IGN);
148 		signal(SIGTERM, SIG_IGN);
149 		signal(SIGHUP, SIG_IGN);
150 	}
151 	openlog("nfsd:", LOG_PID, LOG_DAEMON);
152 	pmap_unset(RPCPROG_NFS, NFS_VER2);
153 	if (udpflag) {
154 		if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
155 			syslog(LOG_ERR, "Can't create socket");
156 			exit(1);
157 		}
158 		saddr.sin_family = AF_INET;
159 		saddr.sin_addr.s_addr = INADDR_ANY;
160 		saddr.sin_port = htons(NFS_PORT);
161 		if (bind(sock, &saddr, sizeof(saddr)) < 0) {
162 			syslog(LOG_ERR, "Can't bind addr");
163 			exit(1);
164 		}
165 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
166 			syslog(LOG_ERR, "Can't register with portmap");
167 			exit(1);
168 		}
169 
170 		/*
171 		 * Send the nfs datagram servers right down into the kernel
172 		 */
173 		for (i = 0; i < udpcnt; i++)
174 			if (fork() == 0) {
175 				ret = nfssvc(sock, &msk, sizeof(msk),
176 						&mtch, sizeof(mtch));
177 				if (ret < 0)
178 					syslog(LOG_ERR, "nfssvc() failed %m");
179 				exit();
180 			}
181 		close(sock);
182 	}
183 
184 	/*
185 	 * Now set up the master STREAM server waiting for tcp connections.
186 	 */
187 	if (tcpflag) {
188 		if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
189 			syslog(LOG_ERR, "Can't create socket");
190 			exit(1);
191 		}
192 		saddr.sin_family = AF_INET;
193 		saddr.sin_addr.s_addr = INADDR_ANY;
194 		saddr.sin_port = htons(NFS_PORT);
195 		if (bind(sock, &saddr, sizeof(saddr)) < 0) {
196 			syslog(LOG_ERR, "Can't bind addr");
197 			exit(1);
198 		}
199 		if (listen(sock, 5) < 0) {
200 			syslog(LOG_ERR, "Listen failed");
201 			exit(1);
202 		}
203 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
204 			syslog(LOG_ERR, "Can't register with portmap");
205 			exit(1);
206 		}
207 		/*
208 		 * Loop forever accepting connections and sending the children
209 		 * into the kernel to service the mounts.
210 		 */
211 		for (;;) {
212 			if ((msgsock = accept(sock, (struct sockaddr *)0,
213 				(int *)0)) < 0) {
214 				syslog(LOG_ERR, "Accept failed: %m");
215 				exit(1);
216 			}
217 			/*
218 			 * Grab child termination status' just so defuncts
219 			 * are not left lying about.
220 			 */
221 			while (wait3(&chldstat, WNOHANG, (struct rusage *)0))
222 				;
223 			len = sizeof(peername);
224 			if (getsockname(msgsock, &peername, &len) < 0) {
225 				syslog(LOG_ERR, "Getsockname failed\n");
226 				exit(1);
227 			}
228 			if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr)
229 				!= mtch.sin_addr.s_addr) {
230 				hp = hphead.ha_next;
231 				while (hp) {
232 					if (peername.sin_addr.s_addr ==
233 						hp->ha_sad)
234 						break;
235 					hp = hp->ha_next;
236 				}
237 				if (hp == NULL) {
238 					shutdown(msgsock, 2);
239 					close(msgsock);
240 					continue;
241 				}
242 			}
243 			if (fork() == 0) {
244 				close(sock);
245 				ret = nfssvc(msgsock, &msk, sizeof(msk),
246 						&mtch, sizeof(mtch));
247 				shutdown(msgsock, 2);
248 				if (ret < 0)
249 					syslog(LOG_NOTICE,
250 					    "Nfssvc STREAM Failed");
251 				exit();
252 			}
253 			close(msgsock);
254 		}
255 	}
256 }
257 
258 usage()
259 {
260 	fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n");
261 	exit(1);
262 }
263