mountd.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 2,539 行 · 第 1/5 页

C
2,539
字号
#ifndef lintstatic	char	*sccsid = "@(#)mountd.c	4.7	(ULTRIX)	4/25/91";#endif lint/************************************************************************ *									* *			Copyright (c) 1986-1990 by			* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************//* *	Portions of this software have been licensed to  *	Digital Equipment Company, Maynard, MA. *	Copyright (c) 1987 Sun Microsystems, Inc.  ALL RIGHTS RESERVED. *//*********************************************************************** * *		Modification History * * 02/11/91 lebel *	Fixed mounting /joe/../jim security hole.  Patched spots where *	mountd wasn't freeing memory.  Added ip addr cache to speed up *	automount -hosts, modified 'imposter' (now 'getclientsname'). * * 11/15/90 lebel *		Fixed bug with non-existant pathname parsing in *		set_exports.  Added smarter rmtab updating, YP netgroup *		caching, and duplicate requests cache. * * 07/02/90 sue *		Made fix to have short host names in /etc/exports. * * 11/10/89 lebel *		Errors now go to syslog.  Showmounts can be done over tcp  *		(tcp can handle arbitrarily long exports lists).  The -d *		option implies the -i option and the -s option implies both *		-i and -d.  Mountd registers itself with the portmapper  *		before forking to prevent the case where nfsds start up *		before mountd has time to register itself.  Hostname  *		comparisons are case insensitive.  Duplicate detection *		is now done by inode # comparison (to detect links). * * 07/21/89 lebel *		Rewrite of mtd_mount() and set_exports() to allow options at *		the directory level.  The -n (no filehandle) exports option *		is no longer employed.  update_exportfsdata() keeps the new *		kernel exports list in sync with the mount daemon's. * * 05/25/89	Suzanne Logcher *		Removed code specific to /etc/svcorder.  File is now *		/etc/svc.conf.  Use libc version of bindup(). * * 11/16/88	Suzanne Logcher *		Fixed de-referencing null pointer bugs in path_check() *		which caused mountd on PMAX to seg fault and core dump. * * 11/10/88	Suzanne Logcher *		Updated with V3.0 changes. * * 07/15/88	Suzanne Logcher *		Fixed QAR 64 bug to continue to parse a directory entry *		in /etc/exports after catching an improper setting of *		an option.  Force a showmount request to rebuild the *		export structure.  Changed usage of -i with bind.  The *		-d flag is for after checking the IP address, see if *		host is in the server domain.  The -s flag does the same *		check but checks if the host is in the server domain or *		a subdomain. * * 06/09/88	Suzanne Logcher *		Added v2.3 fix to not cleanup the export list of *		unexported filesystems and use that info to determine *		whether the getmount info on the filesystem has changed *		thus giving the mountd a "kick" to rebuild the export *		list.  This handles the case when the filesystems have *		changed and the /etc/exports file has NOT been modified *		thus causing the mountd's export list to be out-of-date. *		Upon a second failure with exit with EACESS. * * 04/24/88	Fred Glover *		Add BIND domain specification check for ipaddr_check  * * 03/01/88	Suzanne Logcher *		Rewrite of code.  Use getmountent to build exports *		list, and then read in /etc/exports and build matrix *		of exports with filesystems and directories.  Change *		code in mtd_mount() to parse new list structure.  Add a *		routine, flatten_exports(), to provide full information *		to an EXPORT request.  Linted as best as possible. * * 05/25/87	Joe Amato *		When looking to match the path requested to mount *		loop through exports list looking for an exact match *		if not found, loop through exports list again, but *		look for a match on a subset of the requested path * * 05/19/87	Joe Amato *		Moved some initialization code before fork. *		When looking for a machine in a long group list, only  *		call innetgr after searching complete list to avoid  *		unnecessary YP timeouts. * * 05/06/87	Suzanne Logcher *		Changed M_RONLY to M_EXRONLY * * 03/19/87	Suzanne Logcher *		Added code to setopt to parse options in /etc/exports * * 02/10/87	Suzanne Logcher *		Added code to allow exporting of directories * ***********************************************************************//* NFS mount server */#include <ctype.h>#include <sys/param.h>#include <ufs/fs.h>#include <rpc/rpc.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/file.h>#include <sys/time.h>#include <stdio.h>#include <syslog.h>#include <signal.h>#include <sys/wait.h>#include <sys/ioctl.h>#include <sys/errno.h>#include <sys/dir.h>#include <nfs/nfs.h>#include <rpcsvc/ypclnt.h>#include <rpcsvc/yp_prot.h>#ifdef DEBUG#include "mount.h"#else#include <rpcsvc/mount.h>#endif DEBUG#include <netdb.h>#include <sys/mount.h>#include <nfs/nfs_clnt.h>#include <nfs/vfs.h>#include <strings.h>#include <arpa/nameser.h>#include <resolv.h>#define	EXPORTS	"/etc/exports"#define RMTAB	"/etc/rmtab"#define MAXRMTABLINELEN         (MAXPATHLEN + MAXHOSTNAMELEN + 2)#define	MAXLINE	2048#define MAX_LEVELS  10#define MAXADDRS 8extern int errno;int expand_ng();int innetgr_cache();int check_ng();int getkeys();int mnt();char *exmalloc();struct exports *newex();struct groups *newgroup();char *goto_char();char *realpath();/* * mountd's version of a "struct mountlist". It is the same except * for the added ml_pos field. */struct mountdlist {/* same as XDR mountlist */        char *ml_name;        char *ml_path;        struct mountdlist *ml_nxt;/* private to mountd */        long ml_pos;            /* position of mount entry in RMTAB */};struct ng {             /* netgroup cache */        long ng_stamp;        char *ng_name;        struct hlist *ng_hosts;        struct ng *next_ng;        struct ng *prev_ng;};struct hlist {        char *hname;        struct hlist *next_host;};/* * Mount Reply Cache - save replies, and check the cache to catch * retransmitted requests. *//* *  RPC server duplicate transaction cache flag values */#define DUP_BUSY        0x1     /* transaction in progress */#define DUP_DONE        0x2     /* transaction was completed */#define DUP_FAIL        0x4     /* transaction failed */struct dupreq {        struct in_addr  rc_addr;        /* client address */        u_short         rc_flags;       /* DUP_BUSY, DUP_DONE, DUP_FAIL */        dev_t           rc_dev;         /* device */        u_long          rc_ino;         /* inode number */        u_long          rc_gen;         /* generation number */        struct dupreq   *rc_next;       /* linked list of all entries */        struct dupreq   *rc_chain;      /* hash chain */	char 		*rc_ancname;    /* name of requested path's most					   closely related exported ancestor */};#define KEYHASH(addr,dev,ino,gen)       ((((addr) ^ (dev)) ^ (ino) ^ (gen)) % drhashszminus1)#define KEYTOLIST(addr,dev,ino,gen)     ((struct dupreq *)(drhashtbl[KEYHASH(addr,dev,ino,gen)]))#define REQTOLIST(dr)   KEYTOLIST((dr)->rc_addr.s_addr,(dr)->rc_dev,(dr)->rc_ino, (dr)->rc_gen) /* routine to compare dup cache entries */#define NOTDUP(dr, addr,dev,ino,gen) (dr->rc_addr.s_addr != addr || \                            dr->rc_dev != dev || \                            dr->rc_ino != ino || \                            dr->rc_gen != gen)/* * dupcache_max is the number of cached items.  It is set * based on "system size". It should be large enough to hold * transaction history long enough so that a given entry is still * around for a few retransmissions of that transaction. */#define MINDUPREQS      1024#define MAXDUPREQS      4096struct dupreq **drhashtbl; /* array of heads of hash lists */int drhashsz;              /* number of hash lists */int drhashszminus1;        /* hash modulus */int dupcache_max;struct dupreq *dupreqcache, *drmru;struct dupreq *dupcache_check();struct ng *nglist = NULL;  /* head of netgroup's cache */char *ng_names[100];int num_ngs;static struct mountdlist *mountlist;int rmtab_load();long rmtab_insert(); char myname[BUFSIZ];char mydomain[MAXNAMLEN+1];char *pgmname;char *exportfile = EXPORTS;struct stat exportstat;struct exports *exports = NULL;struct exports *flatexports = NULL;int nfs_portmon = 0;int ipaddr_check = 0;int domain_check = 0;int subdomain_check = 0;struct timeval rmtab_written, now;struct timezone tz;/* * resync rmtab no more often than at 30 minute intervals * sole purpose is to get rid of commented out (unmounted) entries */int   rmtab_sync=1800;/* * Cached netgroups are assumed correct for at least 15 minutes */int ngtimeout = 900; main(argc, argv)char	*argv[];{	SVCXPRT *transp;	char *strchr ();	int fd; /* open fd of rmtab */	pgmname = argv[0];	/*	 * must be superuser to run 	 */	if (geteuid() != 0){		(void) fprintf(stderr, "%s:  must be super user\n", pgmname);		(void) fflush(stderr);		exit(1);	}	while (--argc > 0 ) {		*++argv;		if ((*argv)[0] != '-' || strlen(*argv) != 2) {			usage();		}		switch ((*argv)[1]) {		case 'i':			ipaddr_check++;			break;		case 'd':			ipaddr_check++;			domain_check++;			break;		case 's':			ipaddr_check++;			subdomain_check++;			break;		default:			usage();		}	}	if (openlog("mountd", LOG_PID) < 0)		fprintf(stderr, "mountd: openlog failed\n");	syslog(LOG_ERR, "startup");	/*	 * Initalize the world	 */	if(gethostname(myname, sizeof(myname)) < 0){            /* jaa */		syslog(LOG_ERR, "gethostname: %m");		exit(1);	}	if(getdomainname(mydomain, sizeof(mydomain)) < 0){      /* jaa */		syslog(LOG_ERR, "getdomainname: %m");		exit(1);	}	/*	 * Read rmtab and exports files, build netgroups cache	 */	fd = rmtab_load();	if (mydomain[0] != NULL)        	build_ngcache();#ifdef DEBUG        print_ngcache();#endif DEBUG	set_exports();#ifdef DEBUG	(void) fprintf(stderr, "*** finished loading export list ***\n");#endif DEBUG	gettimeofday(&rmtab_written, &tz);	/*	 * Remove this chunk of code if we ever run under inetd.         * (Make sure rmtab - fd - does not get closed)	 * Also remove the mtd_abort() routine if running under inetd.	 */	{		int s, t;		struct sockaddr_in addr;		int len = sizeof(struct sockaddr_in);		int pid;#ifndef DEBUG		for (t = 0; t < 20; t++)			if (t != fd)				(void) close(t);	 	open("/", 0);	 	dup2(0, 1);	 	dup2(0, 2);#endif DEBUG		if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {			syslog(LOG_ERR, "socket: %m");			exit(1);		}		if (bind(s, &addr, sizeof(addr)) < 0) {			syslog(LOG_ERR, "bind: %m");			exit(1);		}		if (getsockname(s, &addr, &len) != 0) {			syslog(LOG_ERR, "getsockname: %m");			(void) close(s);			exit(1);		}		pmap_unset(MOUNTPROG, MOUNTVERS);		/* 		 * register with portmapper if not started from inetd		 */		pmap_set(MOUNTPROG, MOUNTVERS, IPPROTO_UDP,		    ntohs(addr.sin_port));		if (dup2(s, 0) < 0) {			syslog(LOG_ERR, "dup2: %m");			exit(1);		}#ifndef DEBUG		pid = fork();		if (pid < 0) {			syslog(LOG_ERR, "Cannot fork: %m");			exit(1);		}		if (pid != 0)			exit(0);#endif DEBUG	}	/* End chunk to remove if running under inetd. */	/*	 * Create UDP service	 */	if ((transp = svcudp_create(0)) == NULL) {		syslog(LOG_ERR, "couldn't create UDP transport");		exit(1);	}	if (!svc_register(transp, MOUNTPROG, MOUNTVERS, mnt, 0)) {		syslog(LOG_ERR, "couldn't register MOUNTPROG");		exit(1);	}	/*	 * Create TCP service	 */	if ((transp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) {		syslog(LOG_ERR, "couldn't create TCP transport");		exit(1);	}	if (!svc_register(transp, MOUNTPROG, MOUNTVERS, mnt, IPPROTO_TCP)) {		syslog(LOG_ERR, "couldn't register MOUNTPROG");		exit(1);	}	dupcache_init();  /* dup req cache */	/*	 * Start serving	 */	while(1) {		svc_run();		syslog(LOG_ERR, "Error: svc_run shouldn't have returned");		mtd_abort();	}}/* * Server procedure switch routine */mnt(rqstp, transp)	struct svc_req *rqstp;	SVCXPRT *transp;{#ifdef DEBUG	char *machine;	machine = ((struct authunix_parms *) rqstp->rq_clntcred)->aup_machname;#endif DEBUG	switch(rqstp->rq_proc) {		case NULLPROC:			if (!svc_sendreply(transp, xdr_void, NULL)) {				syslog(LOG_ERR, "couldn't reply to NULL rpc call");				mtd_abort();			}			return;		case MOUNTPROC_MNT:#ifdef DEBUG			(void) fprintf(stderr, "about to do a mount from %s\n", machine);#endif			set_exports();			(void) mtd_mount(rqstp, transp);			return;		case MOUNTPROC_DUMP:#ifdef DEBUG			(void) fprintf(stderr, "about to do a dump from %s\n", machine);#endif			if (!svc_sendreply(transp, xdr_mountlist, &mountlist)) {				syslog(LOG_ERR, "couldn't reply to DUMP rpc call");				mtd_abort();			}			return;		case MOUNTPROC_UMNT:#ifdef DEBUG			(void) fprintf(stderr, "about to do an unmount from %s\n", machine);#endif			(void) mtd_umount(rqstp, transp);			return;		case MOUNTPROC_UMNTALL:#ifdef DEBUG			(void) fprintf(stderr, "about to do an unmountall from %s\n", machine);#endif			mtd_umountall(rqstp, transp);			return;		case MOUNTPROC_EXPORT:		case MOUNTPROC_EXPORTALL:#ifdef DEBUG			(void) fprintf(stderr, "about to do an export from %s\n", machine);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?