908 lines
21 KiB
C
908 lines
21 KiB
C
/*
|
|
* Copyright (c) 1989 The Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to Berkeley by
|
|
* Rick Macklem at The University of Guelph.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#ifndef lint
|
|
char copyright[] =
|
|
"@(#) Copyright (c) 1989 Regents of the University of California.\n\
|
|
All rights reserved.\n";
|
|
#endif not lint
|
|
|
|
#ifndef lint
|
|
/*static char sccsid[] = "from: @(#)mountd.c 5.14 (Berkeley) 2/26/91";*/
|
|
static char rcsid[] = "$Id: mountd.c,v 1.11 1994/01/06 22:48:51 ws Exp $";
|
|
#endif not lint
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/file.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/signal.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <netdb.h>
|
|
#include <rpc/rpc.h>
|
|
#include <rpc/pmap_clnt.h>
|
|
#include <rpc/pmap_prot.h>
|
|
#include <nfs/nfsv2.h>
|
|
#include <rpcsvc/mount.h>
|
|
#include "pathnames.h"
|
|
|
|
struct ufid {
|
|
u_short ufid_len;
|
|
ino_t ufid_ino;
|
|
long ufid_gen;
|
|
};
|
|
/*
|
|
* Structures for keeping the mount list and export list
|
|
*/
|
|
struct mountlist {
|
|
struct mountlist *ml_next;
|
|
char ml_host[MNTNAMLEN+1];
|
|
char ml_dirp[MNTPATHLEN+1];
|
|
};
|
|
|
|
struct exportlist {
|
|
struct exportlist *ex_next;
|
|
struct exportlist *ex_prev;
|
|
struct grouplist *ex_groups;
|
|
int ex_rootuid;
|
|
int ex_exflags;
|
|
int ex_alldirflg;
|
|
dev_t ex_dev;
|
|
char ex_dirp[MNTPATHLEN+1];
|
|
};
|
|
|
|
struct grouplist {
|
|
struct grouplist *gr_next;
|
|
struct hostent *gr_hp;
|
|
};
|
|
|
|
/* Global defs */
|
|
void mntsrv();
|
|
int umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
|
|
void add_mlist(), del_mlist(), get_exportlist(), get_mountlist();
|
|
void send_umntall();
|
|
struct exportlist exphead;
|
|
struct mountlist *mlhead;
|
|
char exname[MAXPATHLEN];
|
|
int def_rootuid = -2;
|
|
int root_only = 1;
|
|
extern int errno;
|
|
|
|
/*
|
|
* Mountd server for NFS mount protocol as described in:
|
|
* NFS: Network File System Protocol Specification, RFC1094, Appendix A
|
|
* The optional arguments are the exports file name
|
|
* default: _PATH_EXPORTS
|
|
* and "-n" to allow nonroot mount.
|
|
*/
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
FILE *pidfile;
|
|
extern int optind;
|
|
extern char *optarg;
|
|
SVCXPRT *transp;
|
|
int c;
|
|
int sock = 0;
|
|
int proto = 0;
|
|
int from_inetd = 1;
|
|
struct sockaddr_in from;
|
|
int fromlen;
|
|
|
|
while ((c = getopt(argc, argv, "n")) != EOF)
|
|
switch (c) {
|
|
case 'n':
|
|
root_only = 0;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
|
|
exit(1);
|
|
};
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
|
|
mlhead = (struct mountlist *)0;
|
|
|
|
if (argc == 1) {
|
|
strncpy(exname, *argv, MAXPATHLEN-1);
|
|
exname[MAXPATHLEN-1] = '\0';
|
|
} else
|
|
strcpy(exname, _PATH_EXPORTS);
|
|
|
|
if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
|
|
from_inetd = 0;
|
|
sock = RPC_ANYSOCK;
|
|
proto = IPPROTO_UDP;
|
|
}
|
|
|
|
if (!from_inetd) {
|
|
daemon(0, 0);
|
|
pmap_unset(MOUNTPROG, MOUNTVERS);
|
|
signal(SIGINT, SIG_IGN);
|
|
signal(SIGQUIT, SIG_IGN);
|
|
}
|
|
|
|
openlog("mountd", LOG_PID, LOG_DAEMON);
|
|
|
|
if ((transp = svcudp_create(sock)) == NULL) {
|
|
syslog(LOG_ERR, "Can't create socket: %m");
|
|
exit(1);
|
|
}
|
|
|
|
if (!svc_register(transp, MOUNTPROG, MOUNTVERS, mntsrv, proto)) {
|
|
syslog(LOG_ERR, "Can't register mount");
|
|
exit(1);
|
|
}
|
|
|
|
get_exportlist();
|
|
get_mountlist();
|
|
|
|
signal(SIGHUP, get_exportlist);
|
|
signal(SIGTERM, send_umntall);
|
|
|
|
pidfile = fopen(_PATH_MOUNTDPID, "w");
|
|
if (pidfile != NULL) {
|
|
fprintf(pidfile, "%d\n", getpid());
|
|
fclose(pidfile);
|
|
}
|
|
|
|
svc_run();
|
|
syslog(LOG_ERR, "Mountd died");
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* The mount rpc service
|
|
*/
|
|
void
|
|
mntsrv(rqstp, transp)
|
|
register struct svc_req *rqstp;
|
|
register SVCXPRT *transp;
|
|
{
|
|
register struct grouplist *grp;
|
|
register u_long **addrp;
|
|
register struct exportlist *ep;
|
|
nfsv2fh_t nfh;
|
|
struct authunix_parms *ucr;
|
|
struct stat stb;
|
|
struct hostent *hp;
|
|
u_long saddr;
|
|
char dirpath[MNTPATHLEN+1];
|
|
int bad = ENOENT;
|
|
int omask;
|
|
uid_t uid = -2;
|
|
|
|
/* Get authorization */
|
|
switch (rqstp->rq_cred.oa_flavor) {
|
|
case AUTH_UNIX:
|
|
ucr = (struct authunix_parms *)rqstp->rq_clntcred;
|
|
uid = ucr->aup_uid;
|
|
break;
|
|
case AUTH_NULL:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
saddr = transp->xp_raddr.sin_addr.s_addr;
|
|
hp = (struct hostent *)0;
|
|
switch (rqstp->rq_proc) {
|
|
case NULLPROC:
|
|
if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
return;
|
|
case MOUNTPROC_MNT:
|
|
if (uid != 0 && root_only) {
|
|
svcerr_weakauth(transp);
|
|
return;
|
|
}
|
|
if (!svc_getargs(transp, xdr_dir, dirpath)) {
|
|
svcerr_decode(transp);
|
|
return;
|
|
}
|
|
|
|
/* Check to see if it's a valid dirpath */
|
|
if (stat(dirpath, &stb) < 0 ||
|
|
(!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode))) {
|
|
if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
return;
|
|
}
|
|
|
|
/* Check in the exports list */
|
|
omask = sigblock(sigmask(SIGHUP));
|
|
ep = exphead.ex_next;
|
|
while (ep != NULL) {
|
|
if (!strcmp(ep->ex_dirp, dirpath) ||
|
|
(stb.st_dev == ep->ex_dev && ep->ex_alldirflg)) {
|
|
grp = ep->ex_groups;
|
|
if (grp == NULL)
|
|
break;
|
|
|
|
/* Check for a host match */
|
|
addrp = (u_long **)grp->gr_hp->h_addr_list;
|
|
for (;;) {
|
|
if (**addrp == saddr)
|
|
break;
|
|
if (*++addrp == NULL)
|
|
if (grp = grp->gr_next) {
|
|
addrp = (u_long **)
|
|
grp->gr_hp->h_addr_list;
|
|
} else {
|
|
bad = EACCES;
|
|
if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
sigsetmask(omask);
|
|
return;
|
|
}
|
|
}
|
|
hp = grp->gr_hp;
|
|
break;
|
|
}
|
|
ep = ep->ex_next;
|
|
}
|
|
sigsetmask(omask);
|
|
if (ep == NULL) {
|
|
bad = EACCES;
|
|
if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
return;
|
|
}
|
|
|
|
/* Get the file handle */
|
|
bzero((caddr_t)&nfh, sizeof(nfh));
|
|
if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
|
|
bad = errno;
|
|
if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
return;
|
|
}
|
|
if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
if (hp == NULL)
|
|
hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
|
|
if (hp)
|
|
add_mlist(hp->h_name, dirpath);
|
|
return;
|
|
case MOUNTPROC_DUMP:
|
|
if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
return;
|
|
case MOUNTPROC_UMNT:
|
|
if (uid != 0 && root_only) {
|
|
svcerr_weakauth(transp);
|
|
return;
|
|
}
|
|
if (!svc_getargs(transp, xdr_dir, dirpath)) {
|
|
svcerr_decode(transp);
|
|
return;
|
|
}
|
|
if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
|
|
if (hp)
|
|
del_mlist(hp->h_name, dirpath);
|
|
return;
|
|
case MOUNTPROC_UMNTALL:
|
|
if (uid != 0 && root_only) {
|
|
svcerr_weakauth(transp);
|
|
return;
|
|
}
|
|
if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
|
|
if (hp)
|
|
del_mlist(hp->h_name, (char *)0);
|
|
return;
|
|
case MOUNTPROC_EXPORT:
|
|
case MOUNTPROC_EXPORTALL:
|
|
get_exportlist();
|
|
if (!svc_sendreply(transp, xdr_explist, (caddr_t)exphead.ex_next))
|
|
syslog(LOG_ERR, "Can't send reply");
|
|
return;
|
|
default:
|
|
svcerr_noproc(transp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Xdr conversion for a dirpath string
|
|
*/
|
|
xdr_dir(xdrsp, dirp)
|
|
XDR *xdrsp;
|
|
char *dirp;
|
|
{
|
|
return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
|
|
}
|
|
|
|
/*
|
|
* Xdr routine to generate fhstatus
|
|
*/
|
|
xdr_fhs(xdrsp, nfh)
|
|
XDR *xdrsp;
|
|
nfsv2fh_t *nfh;
|
|
{
|
|
long ok = 0;
|
|
|
|
if (!xdr_long(xdrsp, &ok))
|
|
return (0);
|
|
return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
|
|
}
|
|
|
|
xdr_mlist(xdrsp, cp)
|
|
XDR *xdrsp;
|
|
caddr_t cp;
|
|
{
|
|
register struct mountlist *mlp;
|
|
int true = 1;
|
|
int false = 0;
|
|
char *strp;
|
|
|
|
mlp = mlhead;
|
|
while (mlp) {
|
|
if (!xdr_bool(xdrsp, &true))
|
|
return (0);
|
|
strp = &mlp->ml_host[0];
|
|
if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
|
|
return (0);
|
|
strp = &mlp->ml_dirp[0];
|
|
if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
|
|
return (0);
|
|
mlp = mlp->ml_next;
|
|
}
|
|
if (!xdr_bool(xdrsp, &false))
|
|
return (0);
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Xdr conversion for export list
|
|
*/
|
|
xdr_explist(xdrsp, cp)
|
|
XDR *xdrsp;
|
|
caddr_t cp;
|
|
{
|
|
register struct exportlist *ep = (struct exportlist *)cp;
|
|
register struct grouplist *grp;
|
|
int true = 1;
|
|
int false = 0;
|
|
char *strp;
|
|
int omask;
|
|
|
|
omask = sigblock(sigmask(SIGHUP));
|
|
while (ep != NULL) {
|
|
if (!xdr_bool(xdrsp, &true))
|
|
goto errout;
|
|
strp = &ep->ex_dirp[0];
|
|
if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
|
|
goto errout;
|
|
grp = ep->ex_groups;
|
|
while (grp != NULL) {
|
|
if (!xdr_bool(xdrsp, &true))
|
|
goto errout;
|
|
strp = grp->gr_hp->h_name;
|
|
if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
|
|
goto errout;
|
|
grp = grp->gr_next;
|
|
}
|
|
if (!xdr_bool(xdrsp, &false))
|
|
goto errout;
|
|
ep = ep->ex_next;
|
|
}
|
|
sigsetmask(omask);
|
|
if (!xdr_bool(xdrsp, &false))
|
|
return (0);
|
|
return (1);
|
|
errout:
|
|
sigsetmask(omask);
|
|
return (0);
|
|
}
|
|
|
|
#define LINESIZ 10240
|
|
char line[LINESIZ];
|
|
|
|
/*
|
|
* Get the export list
|
|
*/
|
|
|
|
void
|
|
get_exportlist()
|
|
{
|
|
register struct hostent *hp, *nhp;
|
|
register char **addrp, **naddrp;
|
|
register int i;
|
|
register struct grouplist *grp;
|
|
register struct exportlist *ep, *ep2;
|
|
struct statfs stfsbuf;
|
|
nfsv2fh_t nfh;
|
|
struct export_args args;
|
|
struct stat sb;
|
|
FILE *inf;
|
|
char *cp, *endcp;
|
|
char savedc;
|
|
int len, dirplen;
|
|
int rootuid, exflags, alldirflg;
|
|
u_long saddr;
|
|
struct exportlist *fep;
|
|
static int first = 0;
|
|
static struct stat last_exportstat;
|
|
|
|
/*
|
|
* Check if the file has changed
|
|
*/
|
|
if (first++) {
|
|
if (stat(exname, &sb) < 0) {
|
|
syslog(LOG_ERR, "stat of export file %s failed. %m", exname);
|
|
ep = exphead.ex_next;
|
|
while (ep != NULL) {
|
|
ep2 = ep;
|
|
ep = ep->ex_next;
|
|
free_exp(ep2);
|
|
}
|
|
return;
|
|
}
|
|
if (last_exportstat.st_mtime == sb.st_mtime)
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* First, get rid of the old list
|
|
*/
|
|
ep = exphead.ex_next;
|
|
while (ep != NULL) {
|
|
ep2 = ep;
|
|
ep = ep->ex_next;
|
|
free_exp(ep2);
|
|
}
|
|
|
|
/*
|
|
* Read in the exports file and build the list, calling
|
|
* exportfs() as we go along
|
|
*/
|
|
exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
|
|
if ((inf = fopen(exname, "r")) == NULL) {
|
|
syslog(LOG_ERR, "Can't open %s", exname);
|
|
exit(2);
|
|
}
|
|
while (fgets(line, LINESIZ, inf)) {
|
|
exflags = MNT_EXPORTED;
|
|
rootuid = def_rootuid;
|
|
alldirflg = 0;
|
|
cp = line;
|
|
nextfield(&cp, &endcp);
|
|
|
|
/*
|
|
* Get file system devno and see if an entry for this
|
|
* file system already exists.
|
|
*/
|
|
savedc = *endcp;
|
|
*endcp = '\0';
|
|
if (stat(cp, &sb) < 0 ||
|
|
(!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode))) {
|
|
syslog(LOG_ERR,
|
|
"Bad Exports File, %s: %s, mountd Failed",
|
|
cp, "Not a directory or regular file");
|
|
exit(2);
|
|
}
|
|
fep = (struct exportlist *)0;
|
|
ep = exphead.ex_next;
|
|
while (ep) {
|
|
if (ep->ex_dev == sb.st_dev) {
|
|
fep = ep;
|
|
break;
|
|
}
|
|
ep = ep->ex_next;
|
|
}
|
|
*endcp = savedc;
|
|
|
|
/*
|
|
* Create new exports list entry
|
|
*/
|
|
len = endcp-cp;
|
|
if (len <= MNTPATHLEN && len > 0) {
|
|
ep = (struct exportlist *)malloc(sizeof(*ep));
|
|
if (ep == NULL)
|
|
goto err;
|
|
ep->ex_next = ep->ex_prev = (struct exportlist *)0;
|
|
ep->ex_groups = (struct grouplist *)0;
|
|
bcopy(cp, ep->ex_dirp, len);
|
|
ep->ex_dirp[len] = '\0';
|
|
dirplen = len;
|
|
} else {
|
|
syslog(LOG_ERR, "Bad Exports File, mountd Failed");
|
|
exit(2);
|
|
}
|
|
cp = endcp;
|
|
nextfield(&cp, &endcp);
|
|
len = endcp-cp;
|
|
while (len > 0) {
|
|
savedc = *endcp;
|
|
*endcp = '\0';
|
|
if (len > MNTNAMLEN)
|
|
goto more;
|
|
if (*cp == '-') {
|
|
do_opt(cp + 1, fep, ep, &exflags, &rootuid,
|
|
&alldirflg);
|
|
goto more;
|
|
}
|
|
if (isdigit(*cp)) {
|
|
saddr = inet_addr(cp);
|
|
if (saddr == -1 ||
|
|
(hp = gethostbyaddr((caddr_t)&saddr,
|
|
sizeof(saddr), AF_INET)) == NULL) {
|
|
syslog(LOG_ERR,
|
|
"Bad Exports File, %s: %s", cp,
|
|
"Gethostbyaddr failed, ignored");
|
|
goto more;
|
|
}
|
|
} else if ((hp = gethostbyname(cp)) == NULL) {
|
|
syslog(LOG_ERR, "Bad Exports File, %s: %s",
|
|
cp, "Gethostbyname failed, ignored");
|
|
goto more;
|
|
}
|
|
grp = (struct grouplist *)
|
|
malloc(sizeof(struct grouplist));
|
|
if (grp == NULL)
|
|
goto err;
|
|
nhp = grp->gr_hp = (struct hostent *)
|
|
malloc(sizeof(struct hostent));
|
|
if (nhp == NULL)
|
|
goto err;
|
|
bcopy((caddr_t)hp, (caddr_t)nhp,
|
|
sizeof(struct hostent));
|
|
i = strlen(hp->h_name)+1;
|
|
nhp->h_name = (char *)malloc(i);
|
|
if (nhp->h_name == NULL)
|
|
goto err;
|
|
bcopy(hp->h_name, nhp->h_name, i);
|
|
addrp = hp->h_addr_list;
|
|
i = 1;
|
|
while (*addrp++)
|
|
i++;
|
|
naddrp = nhp->h_addr_list = (char **)
|
|
malloc(i*sizeof(char *));
|
|
if (naddrp == NULL)
|
|
goto err;
|
|
addrp = hp->h_addr_list;
|
|
while (*addrp) {
|
|
*naddrp = (char *)
|
|
malloc(hp->h_length);
|
|
if (*naddrp == NULL)
|
|
goto err;
|
|
bcopy(*addrp, *naddrp,
|
|
hp->h_length);
|
|
addrp++;
|
|
naddrp++;
|
|
}
|
|
*naddrp = (char *)0;
|
|
grp->gr_next = ep->ex_groups;
|
|
ep->ex_groups = grp;
|
|
more:
|
|
cp = endcp;
|
|
*cp = savedc;
|
|
nextfield(&cp, &endcp);
|
|
len = endcp - cp;
|
|
}
|
|
if (fep == NULL) {
|
|
args.exroot = rootuid;
|
|
cp = (char *)0;
|
|
while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
|
|
mount(MOUNT_EXPORT, ep->ex_dirp,
|
|
stfsbuf.f_flags|(MNT_UPDATE|exflags),
|
|
&args) < 0) {
|
|
/* 08 Sep 92*/ if (cp)
|
|
*cp-- = savedc;
|
|
else
|
|
cp = ep->ex_dirp + dirplen - 1;
|
|
#ifdef OMIT
|
|
if (cp == NULL)
|
|
cp = ep->ex_dirp + dirplen - 1;
|
|
else
|
|
*cp = savedc;
|
|
#endif /* OMIT*/
|
|
/* back up over the last component */
|
|
while (*cp == '/' && cp > ep->ex_dirp)
|
|
cp--;
|
|
/* 08 Sep 92*/ while (cp > ep->ex_dirp && *(cp - 1) != '/')
|
|
cp--;
|
|
if (cp == ep->ex_dirp) {
|
|
syslog(LOG_WARNING,
|
|
"Can't export %s", ep->ex_dirp);
|
|
free_exp(ep);
|
|
goto nextline;
|
|
}
|
|
savedc = *cp;
|
|
*cp = '\0';
|
|
}
|
|
if (cp)
|
|
*cp = savedc;
|
|
ep->ex_rootuid = rootuid;
|
|
ep->ex_exflags = exflags;
|
|
ep->ex_alldirflg = alldirflg;
|
|
} else {
|
|
if (alldirflg || fep->ex_alldirflg) {
|
|
syslog(LOG_WARNING,
|
|
"Can't export alldirs plus other exports");
|
|
free_exp(ep);
|
|
goto nextline;
|
|
}
|
|
ep->ex_rootuid = fep->ex_rootuid;
|
|
ep->ex_exflags = fep->ex_exflags;
|
|
ep->ex_alldirflg = 0;
|
|
}
|
|
if (getfh(ep->ex_dirp, (fhandle_t *)&nfh) < 0) {
|
|
syslog(LOG_WARNING, "Can't export %s", ep->ex_dirp);
|
|
free_exp(ep);
|
|
goto nextline;
|
|
}
|
|
ep->ex_dev = sb.st_dev;
|
|
ep->ex_next = exphead.ex_next;
|
|
ep->ex_prev = &exphead;
|
|
if (ep->ex_next != NULL)
|
|
ep->ex_next->ex_prev = ep;
|
|
exphead.ex_next = ep;
|
|
nextline:
|
|
;
|
|
}
|
|
fclose(inf);
|
|
return;
|
|
err:
|
|
syslog(LOG_ERR, "No more memory: mountd Failed");
|
|
exit(2);
|
|
}
|
|
|
|
/*
|
|
* Parse out the next white space separated field
|
|
*/
|
|
nextfield(cp, endcp)
|
|
char **cp;
|
|
char **endcp;
|
|
{
|
|
register char *p;
|
|
|
|
p = *cp;
|
|
while (*p == ' ' || *p == '\t')
|
|
p++;
|
|
if (*p == '\n' || *p == '\0') {
|
|
*cp = *endcp = p;
|
|
return;
|
|
}
|
|
*cp = p++;
|
|
while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
|
|
p++;
|
|
*endcp = p;
|
|
}
|
|
|
|
/*
|
|
* Parse the option string
|
|
*/
|
|
do_opt(cpopt, fep, ep, exflagsp, rootuidp, alldirflgp)
|
|
register char *cpopt;
|
|
struct exportlist *fep, *ep;
|
|
int *exflagsp, *rootuidp, *alldirflgp;
|
|
{
|
|
register char *cpoptarg, *cpoptend;
|
|
|
|
while (cpopt && *cpopt) {
|
|
if (cpoptend = index(cpopt, ','))
|
|
*cpoptend++ = '\0';
|
|
if (cpoptarg = index(cpopt, '='))
|
|
*cpoptarg++ = '\0';
|
|
if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
|
|
if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
|
|
syslog(LOG_WARNING, "ro failed for %s",
|
|
ep->ex_dirp);
|
|
else
|
|
*exflagsp |= MNT_EXRDONLY;
|
|
} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
|
|
if (cpoptarg && isdigit(*cpoptarg)) {
|
|
*rootuidp = atoi(cpoptarg);
|
|
if (fep && fep->ex_rootuid != *rootuidp)
|
|
syslog(LOG_WARNING,
|
|
"uid failed for %s",
|
|
ep->ex_dirp);
|
|
} else
|
|
syslog(LOG_WARNING,
|
|
"uid failed for %s",
|
|
ep->ex_dirp);
|
|
} else if (!strcmp(cpopt, "alldirs") || !strcmp(cpopt, "a")) {
|
|
*alldirflgp = 1;
|
|
} else
|
|
syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
|
|
ep->ex_dirp);
|
|
cpopt = cpoptend;
|
|
}
|
|
}
|
|
|
|
#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50)
|
|
/*
|
|
* Routines that maintain the remote mounttab
|
|
*/
|
|
void get_mountlist()
|
|
{
|
|
register struct mountlist *mlp, **mlpp;
|
|
register char *eos, *dirp;
|
|
int len;
|
|
char str[STRSIZ];
|
|
FILE *mlfile;
|
|
|
|
if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
|
|
syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
|
|
return;
|
|
}
|
|
mlpp = &mlhead;
|
|
while (fgets(str, STRSIZ, mlfile) != NULL) {
|
|
if ((dirp = index(str, '\t')) == NULL &&
|
|
(dirp = index(str, ' ')) == NULL)
|
|
continue;
|
|
mlp = (struct mountlist *)malloc(sizeof (*mlp));
|
|
len = dirp-str;
|
|
if (len > MNTNAMLEN)
|
|
len = MNTNAMLEN;
|
|
bcopy(str, mlp->ml_host, len);
|
|
mlp->ml_host[len] = '\0';
|
|
while (*dirp == '\t' || *dirp == ' ')
|
|
dirp++;
|
|
if ((eos = index(dirp, '\t')) == NULL &&
|
|
(eos = index(dirp, ' ')) == NULL &&
|
|
(eos = index(dirp, '\n')) == NULL)
|
|
len = strlen(dirp);
|
|
else
|
|
len = eos-dirp;
|
|
if (len > MNTPATHLEN)
|
|
len = MNTPATHLEN;
|
|
bcopy(dirp, mlp->ml_dirp, len);
|
|
mlp->ml_dirp[len] = '\0';
|
|
mlp->ml_next = (struct mountlist *)0;
|
|
*mlpp = mlp;
|
|
mlpp = &mlp->ml_next;
|
|
}
|
|
fclose(mlfile);
|
|
}
|
|
|
|
void del_mlist(hostp, dirp)
|
|
register char *hostp, *dirp;
|
|
{
|
|
register struct mountlist *mlp, **mlpp;
|
|
FILE *mlfile;
|
|
int fnd = 0;
|
|
|
|
mlpp = &mlhead;
|
|
mlp = mlhead;
|
|
while (mlp) {
|
|
if (!strcmp(mlp->ml_host, hostp) &&
|
|
(!dirp || !strcmp(mlp->ml_dirp, dirp))) {
|
|
fnd = 1;
|
|
*mlpp = mlp->ml_next;
|
|
free((caddr_t)mlp);
|
|
}
|
|
mlpp = &mlp->ml_next;
|
|
mlp = mlp->ml_next;
|
|
}
|
|
if (fnd) {
|
|
if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
|
|
syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
|
|
return;
|
|
}
|
|
mlp = mlhead;
|
|
while (mlp) {
|
|
fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
|
|
mlp = mlp->ml_next;
|
|
}
|
|
fclose(mlfile);
|
|
}
|
|
}
|
|
|
|
void add_mlist(hostp, dirp)
|
|
register char *hostp, *dirp;
|
|
{
|
|
register struct mountlist *mlp, **mlpp;
|
|
FILE *mlfile;
|
|
|
|
mlpp = &mlhead;
|
|
mlp = mlhead;
|
|
while (mlp) {
|
|
if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
|
|
return;
|
|
mlpp = &mlp->ml_next;
|
|
mlp = mlp->ml_next;
|
|
}
|
|
mlp = (struct mountlist *)malloc(sizeof (*mlp));
|
|
strncpy(mlp->ml_host, hostp, MNTNAMLEN);
|
|
mlp->ml_host[MNTNAMLEN] = '\0';
|
|
strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
|
|
mlp->ml_dirp[MNTPATHLEN] = '\0';
|
|
mlp->ml_next = (struct mountlist *)0;
|
|
*mlpp = mlp;
|
|
if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
|
|
syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
|
|
return;
|
|
}
|
|
fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
|
|
fclose(mlfile);
|
|
}
|
|
|
|
/*
|
|
* This function is called via. SIGTERM when the system is going down.
|
|
* It sends a broadcast RPCMNT_UMNTALL.
|
|
*/
|
|
void
|
|
send_umntall()
|
|
{
|
|
(void) clnt_broadcast(MOUNTPROG, MOUNTVERS, MOUNTPROC_UMNTALL,
|
|
xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
|
|
exit();
|
|
}
|
|
|
|
umntall_each(resultsp, raddr)
|
|
caddr_t resultsp;
|
|
struct sockaddr_in *raddr;
|
|
{
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
* Free up an exports list component
|
|
*/
|
|
free_exp(ep)
|
|
register struct exportlist *ep;
|
|
{
|
|
register struct grouplist *grp;
|
|
register char **addrp;
|
|
struct grouplist *grp2;
|
|
|
|
grp = ep->ex_groups;
|
|
while (grp != NULL) {
|
|
addrp = grp->gr_hp->h_addr_list;
|
|
while (*addrp)
|
|
free(*addrp++);
|
|
free((caddr_t)grp->gr_hp->h_addr_list);
|
|
free(grp->gr_hp->h_name);
|
|
free((caddr_t)grp->gr_hp);
|
|
grp2 = grp;
|
|
grp = grp->gr_next;
|
|
free((caddr_t)grp2);
|
|
}
|
|
free((caddr_t)ep);
|
|
}
|