xref: /csrg-svn/sbin/mountd/mountd.c (revision 38460)
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
22 char 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
28 static char sccsid[] = "@(#)mountd.c	5.1 (Berkeley) 07/16/89";
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 
54 struct 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  */
62 struct 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 
69 struct 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 
78 struct grouplist {
79 	struct grouplist *gr_next;
80 	char	gr_name[RPCMNT_NAMELEN+1];
81 };
82 
83 /* Global defs */
84 int xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
85 int mntsrv(), get_exportlist();
86 struct exportlist exphead;
87 struct mountlist mlhead;
88 char exname[MAXPATHLEN];
89 int def_rootuid = -2;
90 extern int errno;
91 #ifdef DEBUG
92 int debug = 1;
93 #else
94 int 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  */
105 main(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  */
161 mntsrv(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 
179 fprintf(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 */
193 fprintf(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);
204 fprintf(stderr,"net_addr=0x%x\n",transp->xp_raddr.sin_addr.s_addr);
205 fprintf(stderr,"aft gethost hp=0x%x\n",hp);
206 	switch (rqstp->rq_proc) {
207 	case RPCMNT_MOUNT:
208 fprintf(stderr,"in mnt req\n");
209 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
210 			svcerr_decode(transp);
211 			return;
212 		}
213 
214 fprintf(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 
232 fprintf(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 
262 fprintf(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;
272 ufp = (struct ufid *)&nfh.fh_generic;
273 fprintf(stderr,"ftyp=%d fnum=%d\n",nfh.fh_generic.fh_fsid.val[1],
274 nfh.fh_generic.fh_fsid.val[0]);
275 fprintf(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));
280 fprintf(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  */
352 xdr_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  */
362 xdr_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);
370 fprintf(stderr,"eo xdr_fhs\n");
371 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
372 }
373 
374 xdr_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  */
403 xdr_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);
439 errout:
440 	sigsetmask(omask);
441 	return (0);
442 }
443 
444 #define LINESIZ	10240
445 char line[LINESIZ];
446 
447 /*
448  * Get the export list
449  */
450 get_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;
548 err:
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  */
556 nextfield(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 }
574