date and time created 89/07/16 17:41:49 by mckusick
[unix-history] / usr / src / sbin / mountd / mountd.c
CommitLineData
e3ab21d9
KM
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 are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 */
20
21#ifndef lint
22char copyright[] =
23"@(#) Copyright (c) 1989 Regents of the University of California.\n\
24 All rights reserved.\n";
25#endif not lint
26
27#ifndef lint
28static char sccsid[] = "@(#)mountd.c 5.1 (Berkeley) %G%";
29#endif not lint
30
31#include <stdio.h>
32#include <strings.h>
33#include <syslog.h>
34#include <signal.h>
35#include <fcntl.h>
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/ioctl.h>
39#include <sys/stat.h>
40#include <sys/dir.h>
41#include <sys/uio.h>
42#include <sys/namei.h>
43#include <sys/mount.h>
44#include <sys/socket.h>
45#include <sys/socketvar.h>
46#include <sys/errno.h>
47#include <netdb.h>
48#include <rpc/rpc.h>
49#include <rpc/pmap_clnt.h>
50#include <rpc/pmap_prot.h>
51#include <nfs/rpcv2.h>
52#include <nfs/nfsv2.h>
53
54struct ufid {
55 u_short ufid_len;
56 ino_t ufid_ino;
57 long ufid_gen;
58};
59/*
60 * Structures for keeping the mount list and export list
61 */
62struct mountlist {
63 struct mountlist *ml_next;
64 struct mountlist *ml_prev;
65 char ml_host[RPCMNT_NAMELEN+1];
66 char ml_dirp[RPCMNT_PATHLEN+1];
67};
68
69struct exportlist {
70 struct exportlist *ex_next;
71 struct exportlist *ex_prev;
72 struct grouplist *ex_groups;
73 int ex_rootuid;
74 int ex_exflags;
75 char ex_dirp[RPCMNT_PATHLEN+1];
76};
77
78struct grouplist {
79 struct grouplist *gr_next;
80 char gr_name[RPCMNT_NAMELEN+1];
81};
82
83/* Global defs */
84int xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
85int mntsrv(), get_exportlist();
86struct exportlist exphead;
87struct mountlist mlhead;
88char exname[MAXPATHLEN];
89int def_rootuid = -2;
90extern int errno;
91#ifdef DEBUG
92int debug = 1;
93#else
94int debug = 0;
95#endif
96
97/*
98 * Mountd server for NFS mount protocol as described in:
99 * Networking on the Sun Workstation,
100 * Part #800-1324-03 Rev. B
101 * Network File System Protocol Specification Chap. 3
102 * The optional argument is the exports file name
103 * default: /etc/exports
104 */
105main(argc, argv)
106 int argc;
107 char *argv[];
108{
109 SVCXPRT *transp;
110
111 if (debug == 0) {
112 if (fork())
113 exit(0);
114 { int s;
115 for (s = 0; s < 10; s++)
116 (void) close(s);
117 }
118 (void) open("/", O_RDONLY);
119 (void) dup2(0, 1);
120 (void) dup2(0, 2);
121 { int tt = open("/dev/tty", O_RDWR);
122 if (tt > 0) {
123 ioctl(tt, TIOCNOTTY, (char *)0);
124 close(tt);
125 }
126 }
127 (void) setpgrp(0, 0);
128 signal(SIGTSTP, SIG_IGN);
129 signal(SIGTTIN, SIG_IGN);
130 signal(SIGTTOU, SIG_IGN);
131 signal(SIGINT, SIG_IGN);
132 signal(SIGQUIT, SIG_IGN);
133 signal(SIGTERM, SIG_IGN);
134 }
135 openlog("mountd:", LOG_PID, LOG_DAEMON);
136 mlhead.ml_next = mlhead.ml_prev = (struct mountlist *)0;
137 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
138 if (argc == 2) {
139 strncpy(exname, argv[1], MAXPATHLEN-1);
140 exname[MAXPATHLEN-1] = '\0';
141 } else
142 strcpy(exname, "/etc/exports");
143 get_exportlist();
144 signal(SIGHUP, get_exportlist);
145 if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
146 syslog(LOG_ERR, "Can't create socket");
147 exit(1);
148 }
149 pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
150 if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) {
151 syslog(LOG_ERR, "Can't register mount");
152 exit(1);
153 }
154 svc_run();
155 syslog(LOG_ERR, "Mountd died");
156}
157
158/*
159 * The mount rpc service
160 */
161mntsrv(rqstp, transp)
162 register struct svc_req *rqstp;
163 register SVCXPRT *transp;
164{
165 register struct mountlist *mlp;
166 register struct exportlist *ep;
167 register struct grouplist *grp;
168 struct mountlist *mlp2;
169 nfsv2fh_t nfh;
170 struct authunix_parms *ucr;
171 struct stat stb;
172 struct hostent *hp;
173 struct sockaddr_in saddr;
174 char dirpath[RPCMNT_PATHLEN+1];
175 int ok = 0;
176 int bad = ENOENT;
177 int omask;
178
179fprintf(stderr,"in mntsrv\n");
180 if (rqstp->rq_proc == NULLPROC) {
181 if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
182 syslog(LOG_ERR, "Can't send reply");
183 return;
184 }
185
186 /* Get authorization */
187 switch (rqstp->rq_cred.oa_flavor) {
188 case AUTH_UNIX:
189 ucr = (struct authunix_parms *)rqstp->rq_clntcred;
190 if (ucr->aup_uid == 0)
191 break;
192 /* Fall thru to */
193fprintf(stderr,"weak auth\n");
194 case AUTH_NULL:
195 default:
196 svcerr_weakauth(transp);
197 return;
198 }
199
200 saddr.sin_family = AF_INET;
201 saddr.sin_addr.s_addr = ntohl(transp->xp_raddr.sin_addr.s_addr);
202 saddr.sin_port = 0;
203 hp = gethostbyaddr((caddr_t)&saddr, transp->xp_addrlen, AF_INET);
204fprintf(stderr,"net_addr=0x%x\n",transp->xp_raddr.sin_addr.s_addr);
205fprintf(stderr,"aft gethost hp=0x%x\n",hp);
206 switch (rqstp->rq_proc) {
207 case RPCMNT_MOUNT:
208fprintf(stderr,"in mnt req\n");
209 if (!svc_getargs(transp, xdr_dir, dirpath)) {
210 svcerr_decode(transp);
211 return;
212 }
213
214fprintf(stderr,"dirpath=%s\n",dirpath);
215 /* If no hostname, return err */
216#ifdef notdef
217 if (hp == NULL) {
218 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
219 syslog(LOG_ERR, "Can't send reply");
220 return;
221 }
222
223#endif
224 /* Check to see if it's a valid dirpath */
225 if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) !=
226 S_IFDIR) {
227 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
228 syslog(LOG_ERR, "Can't send reply");
229 return;
230 }
231
232fprintf(stderr,"Look in exports list\n");
233 /* Check in the exports list */
234 omask = sigblock(sigmask(SIGHUP));
235 ep = exphead.ex_next;
236 while (ep != NULL) {
237 if (!strcmp(ep->ex_dirp, dirpath)) {
238 grp = ep->ex_groups;
239 if (grp == NULL)
240 break;
241 while (grp != NULL) {
242 if (!strcmp(grp->gr_name, hp->h_name))
243 break;
244 grp = grp->gr_next;
245 }
246 bad = EACCES;
247 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
248 syslog(LOG_ERR, "Can't send reply");
249 sigsetmask(omask);
250 return;
251 }
252 ep = ep->ex_next;
253 }
254 sigsetmask(omask);
255 if (ep == NULL) {
256 bad = EACCES;
257 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
258 syslog(LOG_ERR, "Can't send reply");
259 return;
260 }
261
262fprintf(stderr,"get file handle\n");
263 /* Get the file handle */
264 bzero((caddr_t)&nfh, sizeof(nfh));
265 if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
266 bad = errno;
267 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
268 syslog(LOG_ERR, "Can't send reply");
269 return;
270 }
271{ struct ufid *ufp;
272ufp = (struct ufid *)&nfh.fh_generic;
273fprintf(stderr,"ftyp=%d fnum=%d\n",nfh.fh_generic.fh_fsid.val[1],
274nfh.fh_generic.fh_fsid.val[0]);
275fprintf(stderr,"fid num=%d gen=%d\n",ufp->ufid_ino,ufp->ufid_gen);
276}
277 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
278 syslog(LOG_ERR, "Can't send reply");
279 mlp = (struct mountlist *)malloc(sizeof(struct mountlist));
280fprintf(stderr,"add to list\n");
281#ifdef notdef
282 if (mlp != NULL) {
283 strcpy(mlp->ml_host, hp->h_name);
284 strcpy(mlp->ml_dirp, dirpath);
285 mlp->ml_prev = &mlhead;
286 mlp->ml_next = mlhead.ml_next;
287 if (mlhead.ml_next != NULL)
288 mlhead.ml_next->ml_prev = mlp;
289 mlhead.ml_next = mlp;
290 }
291#endif
292 return;
293 case RPCMNT_DUMP:
294 if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
295 syslog(LOG_ERR, "Can't send reply");
296 return;
297 case RPCMNT_UMOUNT:
298 if (!svc_getargs(transp, xdr_dir, dirpath)) {
299 svcerr_decode(transp);
300 return;
301 }
302 if (hp != NULL) {
303 mlp = mlhead.ml_next;
304 while (mlp != NULL) {
305 if (!strcmp(mlp->ml_host, hp->h_name) &&
306 !strcmp(mlp->ml_dirp, dirpath)) {
307 mlp->ml_prev->ml_next = mlp->ml_next;
308 if (mlp->ml_next != NULL)
309 mlp->ml_next->ml_prev =
310 mlp->ml_prev;
311 free((caddr_t)mlp);
312 break;
313 }
314 mlp = mlp->ml_next;
315 }
316 }
317 if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
318 syslog(LOG_ERR, "Can't send reply");
319 return;
320 case RPCMNT_UMNTALL:
321 if (hp != NULL) {
322 mlp = mlhead.ml_next;
323 while (mlp != NULL) {
324 if (!strcmp(mlp->ml_host, hp->h_name)) {
325 mlp2 = mlp;
326 mlp->ml_prev->ml_next = mlp->ml_next;
327 if (mlp->ml_next != NULL)
328 mlp->ml_next->ml_prev =
329 mlp->ml_prev;
330 mlp = mlp->ml_next;
331 free((caddr_t)mlp2);
332 } else
333 mlp = mlp->ml_next;
334 }
335 }
336 if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
337 syslog(LOG_ERR, "Can't send reply");
338 return;
339 case RPCMNT_EXPORT:
340 if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
341 syslog(LOG_ERR, "Can't send reply");
342 return;
343 default:
344 svcerr_noproc(transp);
345 return;
346 }
347}
348
349/*
350 * Xdr conversion for a dirpath string
351 */
352xdr_dir(xdrsp, dirp)
353 XDR *xdrsp;
354 char *dirp;
355{
356 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
357}
358
359/*
360 * Xdr routine to generate fhstatus
361 */
362xdr_fhs(xdrsp, nfh)
363 XDR *xdrsp;
364 nfsv2fh_t *nfh;
365{
366 int ok = 0;
367
368 if (!xdr_long(xdrsp, &ok))
369 return (0);
370fprintf(stderr,"eo xdr_fhs\n");
371 return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
372}
373
374xdr_mlist(xdrsp, cp)
375 XDR *xdrsp;
376 caddr_t cp;
377{
378 register struct mountlist *mlp;
379 int true = 1;
380 int false = 0;
381 char *strp;
382
383 mlp = mlhead.ml_next;
384 while (mlp != NULL) {
385 if (!xdr_bool(xdrsp, &true))
386 return (0);
387 strp = &mlp->ml_host[0];
388 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
389 return (0);
390 strp = &mlp->ml_dirp[0];
391 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
392 return (0);
393 mlp = mlp->ml_next;
394 }
395 if (!xdr_bool(xdrsp, &false))
396 return (0);
397 return (1);
398}
399
400/*
401 * Xdr conversion for export list
402 */
403xdr_explist(xdrsp, cp)
404 XDR *xdrsp;
405 caddr_t cp;
406{
407 register struct exportlist *ep;
408 register struct grouplist *grp;
409 int true = 1;
410 int false = 0;
411 char *strp;
412 int omask;
413
414 omask = sigblock(sigmask(SIGHUP));
415 ep = exphead.ex_next;
416 while (ep != NULL) {
417 if (!xdr_bool(xdrsp, &true))
418 goto errout;
419 strp = &ep->ex_dirp[0];
420 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
421 goto errout;
422 grp = ep->ex_groups;
423 while (grp != NULL) {
424 if (!xdr_bool(xdrsp, &true))
425 goto errout;
426 strp = &grp->gr_name[0];
427 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
428 goto errout;
429 grp = grp->gr_next;
430 }
431 if (!xdr_bool(xdrsp, &false))
432 goto errout;
433 ep = ep->ex_next;
434 }
435 sigsetmask(omask);
436 if (!xdr_bool(xdrsp, &false))
437 return (0);
438 return (1);
439errout:
440 sigsetmask(omask);
441 return (0);
442}
443
444#define LINESIZ 10240
445char line[LINESIZ];
446
447/*
448 * Get the export list
449 */
450get_exportlist()
451{
452 register struct exportlist *ep, *ep2;
453 register struct grouplist *grp, *grp2;
454 FILE *inf;
455 char *cp, *endcp;
456 int len;
457 int rootuid, exflags;
458
459 /*
460 * First, get rid of the old list
461 */
462 ep = exphead.ex_next;
463 while (ep != NULL) {
464 grp = ep->ex_groups;
465 while (grp != NULL) {
466 grp2 = grp;
467 grp = grp->gr_next;
468 free((caddr_t)grp2);
469 }
470 ep2 = ep;
471 ep = ep->ex_next;
472 free((caddr_t)ep2);
473 }
474
475 /*
476 * Read in the exports file and build the list, calling
477 * exportfs() as we go along
478 */
479 exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
480 if ((inf = fopen(exname, "r")) == NULL) {
481 syslog(LOG_ERR, "Can't open %s", exname);
482 exit(2);
483 }
484 while (fgets(line, LINESIZ, inf)) {
485 exflags = 0;
486 rootuid = def_rootuid;
487 cp = line;
488 nextfield(&cp, &endcp);
489 len = endcp-cp;
490 if (len <= RPCMNT_PATHLEN && len > 0) {
491 ep = (struct exportlist *)malloc(sizeof(*ep));
492 ep->ex_next = ep->ex_prev = (struct exportlist *)0;
493 ep->ex_groups = (struct grouplist *)0;
494 bcopy(cp, ep->ex_dirp, len);
495 ep->ex_dirp[len] = '\0';
496 } else
497 goto err;
498 cp = endcp;
499 nextfield(&cp, &endcp);
500 len = endcp-cp;
501 while (len > 0) {
502 if (len <= RPCMNT_NAMELEN) {
503 if (*cp == '-') {
504 cp++;
505 switch (*cp) {
506 case 'o':
507 exflags |= M_EXRDONLY;
508 break;
509 case 'r':
510 if (*++cp == '=')
511 rootuid = atoi(++cp);
512 break;
513 default:
514 syslog(LOG_WARNING,
515 "Bad -%c option in %s",
516 *cp, exname);
517 break;
518 };
519 } else {
520 grp = (struct grouplist *)malloc(*grp);
521 if (grp == NULL)
522 goto err;
523 bcopy(cp, grp->gr_name, len);
524 grp->gr_name[len] = '\0';
525 grp->gr_next = ep->ex_groups;
526 ep->ex_groups = grp;
527 }
528 }
529 cp = endcp;
530 nextfield(&cp, &endcp);
531 len = endcp-cp;
532 }
533 if (exportfs(ep->ex_dirp, rootuid, exflags) < 0) {
534 syslog(LOG_WARNING, "Can't export %s", ep->ex_dirp);
535 free((caddr_t)ep);
536 } else {
537 ep->ex_rootuid = rootuid;
538 ep->ex_exflags = exflags;
539 ep->ex_next = exphead.ex_next;
540 ep->ex_prev = &exphead;
541 if (ep->ex_next != NULL)
542 ep->ex_next->ex_prev = ep;
543 exphead.ex_next = ep;
544 }
545 }
546 fclose(inf);
547 return;
548err:
549 syslog(LOG_ERR, "Bad /etc/exports, mountd Failed");
550 exit(2);
551}
552
553/*
554 * Parse out the next white space separated field
555 */
556nextfield(cp, endcp)
557 char **cp;
558 char **endcp;
559{
560 register char *p;
561
562 p = *cp;
563 while (*p == ' ' || *p == '\t')
564 p++;
565 if (*p == '\n' || *p == '\0') {
566 *cp = *endcp = p;
567 return;
568 }
569 *cp = p++;
570 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
571 p++;
572 *endcp = p;
573}