avoid deferencing null pointers -- breaks on Solaris (printf is dumb)
[unix-history] / usr / src / sbin / nfsd / nfsd.c
CommitLineData
e3ab21d9 1/*
da519673
KB
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
e3ab21d9
KM
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
70ab3c27 8 * %sccs.include.redist.c%
e3ab21d9
KM
9 */
10
11#ifndef lint
da519673
KB
12static char copyright[] =
13"@(#) Copyright (c) 1989, 1993\n\
14 The Regents of the University of California. All rights reserved.\n";
e3ab21d9
KM
15#endif not lint
16
17#ifndef lint
da519673 18static char sccsid[] = "@(#)nfsd.c 8.1 (Berkeley) %G%";
e3ab21d9
KM
19#endif not lint
20
9a8f56c5
KM
21#include <stdio.h>
22#include <signal.h>
23#include <fcntl.h>
24#include <strings.h>
25#include <pwd.h>
26#include <grp.h>
e3ab21d9 27#include <sys/types.h>
9a8f56c5
KM
28#include <sys/syslog.h>
29#include <sys/param.h>
30#include <sys/errno.h>
e3ab21d9
KM
31#include <sys/ioctl.h>
32#include <sys/stat.h>
af62051f 33#include <sys/wait.h>
9a8f56c5
KM
34#include <sys/uio.h>
35#include <sys/namei.h>
36#include <sys/ucred.h>
e3ab21d9
KM
37#include <sys/mount.h>
38#include <sys/socket.h>
39#include <sys/socketvar.h>
e3ab21d9
KM
40#include <rpc/rpc.h>
41#include <rpc/pmap_clnt.h>
42#include <rpc/pmap_prot.h>
9a8f56c5
KM
43#ifdef ISO
44#include <netiso/iso.h>
45#endif
e3ab21d9
KM
46#include <nfs/rpcv2.h>
47#include <nfs/nfsv2.h>
9a8f56c5
KM
48#include <nfs/nfs.h>
49#ifdef KERBEROS
dbbed105 50#include <kerberosIV/des.h>
9a8f56c5
KM
51#include <kerberosIV/krb.h>
52#endif
e3ab21d9
KM
53
54/* Global defs */
55#ifdef DEBUG
56#define syslog(e, s) fprintf(stderr,(s))
bad1fdd6 57int debug = 1;
e3ab21d9 58#else
bad1fdd6 59int debug = 0;
e3ab21d9 60#endif
9a8f56c5
KM
61struct nfsd_srvargs nsd;
62extern int errno;
bad1fdd6
MK
63char **Argv = NULL; /* pointer to argument vector */
64char *LastArg = NULL; /* end of argv */
65void reapchild();
e3ab21d9 66
9a8f56c5
KM
67#ifdef KERBEROS
68char lnam[ANAME_SZ];
69KTEXT_ST kt;
70AUTH_DAT auth;
71char inst[INST_SZ];
72#endif /* KERBEROS */
73
e3ab21d9
KM
74/*
75 * Nfs server daemon mostly just a user context for nfssvc()
76 * 1 - do file descriptor and signal cleanup
9a8f56c5
KM
77 * 2 - fork the nfsd(s)
78 * 3 - create server socket(s)
79 * 4 - register socket with portmap
80 * For connectionless protocols, just pass the socket into the kernel via.
81 * nfssvc().
af62051f 82 * For connection based sockets, loop doing accepts. When you get a new socket
9a8f56c5 83 * from accept, pass the msgsock into the kernel via. nfssvc().
af62051f 84 * The arguments are:
af62051f 85 * -u - support udp nfs clients
9a8f56c5
KM
86 * -t - support tcp nfs clients
87 * -c - support iso cltp clients
88 * -r - reregister with portmapper
89 * followed by "n" which is the number of nfsds' to fork off
e3ab21d9 90 */
bad1fdd6 91main(argc, argv, envp)
e3ab21d9 92 int argc;
bad1fdd6 93 char *argv[], *envp[];
e3ab21d9
KM
94{
95 register int i;
9a8f56c5
KM
96 register char *cp, **cpp;
97 register struct ucred *cr = &nsd.nsd_cr;
98 struct passwd *pwd;
99 struct group *grp;
100 int sock, msgsock, tcpflag = 0, udpflag = 0, ret, len;
101 int cltpflag = 0, tp4flag = 0, tpipflag = 0, connect_type_cnt = 0;
102 int maxsock, tcpsock, tp4sock, tpipsock, nfsdcnt = 4;
103 int nfssvc_flag, opt, on = 1, reregister = 0;
104 struct sockaddr_in inetaddr, inetpeer;
105#ifdef ISO
106 struct sockaddr_iso isoaddr, isopeer;
107#endif
108 struct nfsd_args nfsdargs;
109 fd_set ready, sockbits;
af62051f
KM
110 extern int optind;
111 extern char *optarg;
bad1fdd6
MK
112
113 /*
114 * Save start and extent of argv for setproctitle.
115 */
bad1fdd6
MK
116 Argv = argv;
117 if (envp == 0 || *envp == 0)
118 envp = argv;
119 while (*envp)
120 envp++;
121 LastArg = envp[-1] + strlen(envp[-1]);
9a8f56c5 122 while ((opt = getopt(argc, argv, "utcr")) != EOF)
af62051f 123 switch (opt) {
9a8f56c5
KM
124 case 'u':
125 udpflag++;
bad1fdd6 126 break;
af62051f
KM
127 case 't':
128 tcpflag++;
af62051f 129 break;
9a8f56c5
KM
130 case 'r':
131 reregister++;
132 break;
133#ifdef ISO
134 case 'c':
135 cltpflag++;
136 break;
137#ifdef notyet
138 case 'i':
139 tp4cnt++;
af62051f 140 break;
9a8f56c5
KM
141 case 'p':
142 tpipcnt++;
143 break;
144#endif /* notyet */
145#endif /* ISO */
af62051f
KM
146 default:
147 case '?':
148 usage();
9a8f56c5
KM
149 };
150 if (optind < argc)
151 nfsdcnt = atoi(argv[optind]);
152 if (nfsdcnt < 1 || nfsdcnt > 20)
153 nfsdcnt = 4;
bad1fdd6 154
e3ab21d9 155 if (debug == 0) {
43d42ac6 156 daemon(0, 0);
e3ab21d9
KM
157 signal(SIGINT, SIG_IGN);
158 signal(SIGQUIT, SIG_IGN);
159 signal(SIGTERM, SIG_IGN);
160 signal(SIGHUP, SIG_IGN);
161 }
bad1fdd6
MK
162 signal(SIGCHLD, reapchild);
163
164 if (reregister) {
165 if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP,
166 NFS_PORT)) {
167 fprintf(stderr,
168 "Can't register with portmap for UDP\n");
169 exit(1);
170 }
171 if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP,
172 NFS_PORT)) {
173 fprintf(stderr,
174 "Can't register with portmap for TCP\n");
175 exit(1);
176 }
177 exit(0);
178 }
e3ab21d9 179 openlog("nfsd:", LOG_PID, LOG_DAEMON);
9a8f56c5
KM
180
181 for (i = 0; i < nfsdcnt; i++)
182 if (fork() == 0) {
183 setproctitle("nfsd-srv");
184 nfssvc_flag = NFSSVC_NFSD;
185 nsd.nsd_nfsd = (struct nfsd *)0;
186#ifdef KERBEROS
187 nsd.nsd_authstr = (char *)kt.dat;
bad1fdd6 188#endif
9a8f56c5
KM
189 while (nfssvc(nfssvc_flag, (caddr_t)&nsd) < 0) {
190 if (errno == ENEEDAUTH) {
191 nfssvc_flag = (NFSSVC_NFSD | NFSSVC_AUTHINFAIL);
192#ifdef KERBEROS
193 kt.length = nsd.nsd_authlen;
194 kt.mbz = 0;
195 strcpy(inst, "*");
196 if (krb_rd_req(&kt, "rcmd", inst, nsd.nsd_haddr,
197 &auth, "") == RD_AP_OK &&
198 krb_kntoln(&auth, lnam) == KSUCCESS &&
199 (pwd = getpwnam(lnam))) {
200 cr->cr_uid = pwd->pw_uid;
201 cr->cr_groups[0] = pwd->pw_gid;
202 cr->cr_ngroups = 1;
203 setgrent();
204 while (grp = getgrent()) {
205 if (grp->gr_gid == cr->cr_groups[0])
206 continue;
207 cpp = grp->gr_mem;
208 while (*cpp) {
209 if (!strcmp(*cpp, lnam))
210 break;
211 cpp++;
212 }
213 if (*cpp) {
214 cr->cr_groups[cr->cr_ngroups++] = grp->gr_gid;
215 if (cr->cr_ngroups == NGROUPS)
216 break;
217 }
218 }
219 endgrent();
220 nfssvc_flag = (NFSSVC_NFSD | NFSSVC_AUTHIN);
221 }
222#endif /* KERBEROS */
223 } else {
9a8f56c5
KM
224 syslog(LOG_ERR, "Nfsd died %m");
225 exit(1);
226 }
227 }
228 exit();
229 }
230
231 /*
232 * If we are serving udp, set up the socket.
233 */
af62051f
KM
234 if (udpflag) {
235 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
9a8f56c5 236 syslog(LOG_ERR, "Can't create udp socket");
af62051f
KM
237 exit(1);
238 }
9a8f56c5
KM
239 inetaddr.sin_family = AF_INET;
240 inetaddr.sin_addr.s_addr = INADDR_ANY;
241 inetaddr.sin_port = htons(NFS_PORT);
242 inetaddr.sin_len = sizeof(inetaddr);
243 if (bind(sock, (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
244 syslog(LOG_ERR, "Can't bind udp addr");
af62051f
KM
245 exit(1);
246 }
247 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
9a8f56c5
KM
248 syslog(LOG_ERR, "Can't register with udp portmap");
249 exit(1);
250 }
251 nfsdargs.sock = sock;
252 nfsdargs.name = (caddr_t)0;
253 nfsdargs.namelen = 0;
254 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
255 syslog(LOG_ERR, "Can't Add UDP socket");
af62051f
KM
256 exit(1);
257 }
9a8f56c5
KM
258 close(sock);
259 }
260
261 /*
262 * If we are serving cltp, set up the socket.
263 */
264#ifdef ISO
265 if (cltpflag) {
266 if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
267 syslog(LOG_ERR, "Can't create cltp socket");
268 exit(1);
269 }
270 bzero((caddr_t)&isoaddr, sizeof (isoaddr));
271 isoaddr.siso_family = AF_ISO;
272 isoaddr.siso_tlen = 2;
273 cp = TSEL(&isoaddr);
274 *cp++ = (NFS_PORT >> 8);
275 *cp = (NFS_PORT & 0xff);
276 isoaddr.siso_len = sizeof(isoaddr);
277 if (bind(sock, (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
278 syslog(LOG_ERR, "Can't bind cltp addr");
279 exit(1);
280 }
281#ifdef notyet
af62051f 282 /*
9a8f56c5
KM
283 * Someday this should probably use "rpcbind", the son of
284 * portmap.
af62051f 285 */
9a8f56c5
KM
286 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
287 syslog(LOG_ERR, "Can't register with udp portmap");
288 exit(1);
289 }
290#endif /* notyet */
291 nfsdargs.sock = sock;
292 nfsdargs.name = (caddr_t)0;
293 nfsdargs.namelen = 0;
294 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
295 syslog(LOG_ERR, "Can't Add UDP socket");
296 exit();
297 }
af62051f 298 close(sock);
e3ab21d9 299 }
9a8f56c5 300#endif /* ISO */
af62051f
KM
301
302 /*
9a8f56c5 303 * Now set up the master server socket waiting for tcp connections.
af62051f 304 */
9a8f56c5 305 FD_ZERO(&sockbits);
af62051f 306 if (tcpflag) {
9a8f56c5
KM
307 if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
308 syslog(LOG_ERR, "Can't create tcp socket");
309 exit(1);
310 }
311 if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR,
312 (char *) &on, sizeof(on)) < 0)
313 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
314 inetaddr.sin_family = AF_INET;
315 inetaddr.sin_addr.s_addr = INADDR_ANY;
316 inetaddr.sin_port = htons(NFS_PORT);
317 inetaddr.sin_len = sizeof (inetaddr);
318 if (bind(tcpsock, (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
319 syslog(LOG_ERR, "Can't bind tcp addr");
320 exit(1);
321 }
322 if (listen(tcpsock, 5) < 0) {
323 syslog(LOG_ERR, "Listen failed");
324 exit(1);
325 }
326 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
327 syslog(LOG_ERR, "Can't register tcp with portmap");
328 exit(1);
329 }
330 FD_SET(tcpsock, &sockbits);
331 maxsock = tcpsock;
332 connect_type_cnt++;
333 }
bad1fdd6 334
9a8f56c5
KM
335#ifdef notyet
336 /*
337 * Now set up the master server socket waiting for tp4 connections.
338 */
339 if (tp4flag) {
340 if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
341 syslog(LOG_ERR, "Can't create tp4 socket");
af62051f
KM
342 exit(1);
343 }
9a8f56c5 344 if (setsockopt(tp4sock, SOL_SOCKET, SO_REUSEADDR,
bad1fdd6
MK
345 (char *) &on, sizeof(on)) < 0)
346 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
9a8f56c5
KM
347 bzero((caddr_t)&isoaddr, sizeof (isoaddr));
348 isoaddr.siso_family = AF_ISO;
349 isoaddr.siso_tlen = 2;
350 cp = TSEL(&isoaddr);
351 *cp++ = (NFS_PORT >> 8);
352 *cp = (NFS_PORT & 0xff);
353 isoaddr.siso_len = sizeof(isoaddr);
354 if (bind(tp4sock, (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
355 syslog(LOG_ERR, "Can't bind tp4 addr");
af62051f
KM
356 exit(1);
357 }
9a8f56c5 358 if (listen(tp4sock, 5) < 0) {
af62051f
KM
359 syslog(LOG_ERR, "Listen failed");
360 exit(1);
361 }
9a8f56c5
KM
362 /*
363 * Someday this should probably use "rpcbind".
364 */
af62051f 365 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
9a8f56c5
KM
366 syslog(LOG_ERR, "Can't register tcp with portmap");
367 exit(1);
368 }
369 FD_SET(tp4sock, &sockbits);
370 maxsock = tp4sock;
371 connect_type_cnt++;
372 }
373
374 /*
375 * Now set up the master server socket waiting for tpip connections.
376 */
377 if (tpipflag) {
378 if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
379 syslog(LOG_ERR, "Can't create tpip socket");
380 exit(1);
381 }
382 if (setsockopt(tpipsock, SOL_SOCKET, SO_REUSEADDR,
383 (char *) &on, sizeof(on)) < 0)
384 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
385 inetaddr.sin_family = AF_INET;
386 inetaddr.sin_addr.s_addr = INADDR_ANY;
387 inetaddr.sin_port = htons(NFS_PORT);
388 inetaddr.sin_len = sizeof (inetaddr);
389 if (bind(tpipsock, (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
390 syslog(LOG_ERR, "Can't bind tcp addr");
391 exit(1);
392 }
393 if (listen(tpipsock, 5) < 0) {
394 syslog(LOG_ERR, "Listen failed");
af62051f
KM
395 exit(1);
396 }
397 /*
9a8f56c5 398 * Someday this should use "rpcbind"
af62051f 399 */
9a8f56c5
KM
400 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
401 syslog(LOG_ERR, "Can't register tcp with portmap");
402 exit(1);
403 }
404 FD_SET(tpipsock, &sockbits);
405 maxsock = tpipsock;
406 connect_type_cnt++;
407 }
408#endif /* notyet */
409
410 if (connect_type_cnt == 0)
411 exit();
412 setproctitle("nfsd-master");
413 /*
414 * Loop forever accepting connections and passing the sockets
415 * into the kernel for the mounts.
416 */
417 for (;;) {
418 ready = sockbits;
419 if (connect_type_cnt > 1) {
420 if (select(maxsock + 1, &ready, (fd_set *)0,
421 (fd_set *)0, (struct timeval *)0) < 1) {
422 syslog(LOG_ERR, "Select failed");
423 exit(1);
424 }
425 }
426 if (tcpflag && FD_ISSET(tcpsock, &ready)) {
427 len = sizeof(inetpeer);
428 if ((msgsock = accept(tcpsock,
429 (struct sockaddr *)&inetpeer, &len)) < 0) {
bad1fdd6 430 syslog(LOG_ERR, "Accept failed: %m");
af62051f
KM
431 exit(1);
432 }
d674eb63
KM
433 bzero((char *)inetpeer.sin_zero,
434 sizeof(inetpeer.sin_zero));
9a8f56c5
KM
435 if (setsockopt(msgsock, SOL_SOCKET,
436 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
437 syslog(LOG_ERR,
438 "setsockopt SO_KEEPALIVE: %m");
439 nfsdargs.sock = msgsock;
440 nfsdargs.name = (caddr_t)&inetpeer;
d674eb63 441 nfsdargs.namelen = sizeof(inetpeer);
9a8f56c5
KM
442 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
443 close(msgsock);
444 }
445#ifdef notyet
446 if (tp4flag && FD_ISSET(tp4sock, &ready)) {
447 len = sizeof(isopeer);
448 if ((msgsock = accept(tp4sock,
449 (struct sockaddr *)&isopeer, &len)) < 0) {
450 syslog(LOG_ERR, "Accept failed: %m");
451 exit(1);
af62051f 452 }
9a8f56c5
KM
453 if (setsockopt(msgsock, SOL_SOCKET,
454 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
455 syslog(LOG_ERR,
456 "setsockopt SO_KEEPALIVE: %m");
457 nfsdargs.sock = msgsock;
458 nfsdargs.name = (caddr_t)&isopeer;
459 nfsdargs.namelen = len;
460 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
461 close(msgsock);
462 }
463 if (tpipflag && FD_ISSET(tpipsock, &ready)) {
464 len = sizeof(inetpeer);
465 if ((msgsock = accept(tpipsock,
466 (struct sockaddr *)&inetpeer, &len)) < 0) {
467 syslog(LOG_ERR, "Accept failed: %m");
362d7dce 468 exit(1);
af62051f 469 }
9a8f56c5
KM
470 if (setsockopt(msgsock, SOL_SOCKET,
471 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
472 syslog(LOG_ERR,
473 "setsockopt SO_KEEPALIVE: %m");
474 nfsdargs.sock = msgsock;
475 nfsdargs.name = (caddr_t)&inetpeer;
476 nfsdargs.namelen = len;
477 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
af62051f
KM
478 close(msgsock);
479 }
9a8f56c5 480#endif /* notyet */
1b3a818d 481 }
af62051f
KM
482}
483
484usage()
485{
9a8f56c5 486 fprintf(stderr, "nfsd [-u] [-t] [-c] [-r] [num_nfsds]\n");
af62051f 487 exit(1);
e3ab21d9 488}
bad1fdd6
MK
489
490void
491reapchild()
492{
493
494 while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL))
495 ;
496}
497
9a8f56c5 498setproctitle(a)
bad1fdd6 499 char *a;
bad1fdd6
MK
500{
501 register char *cp;
502 char buf[80];
503
504 cp = Argv[0];
9a8f56c5 505 (void) sprintf(buf, "%s", a);
bad1fdd6
MK
506 (void) strncpy(cp, buf, LastArg - cp);
507 cp += strlen(cp);
508 while (cp < LastArg)
509 *cp++ = ' ';
510}