* Copyright (c) 1989 The Regents of the University of California.
* 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
* 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
"@(#) Copyright (c) 1989 Regents of the University of California.\n\
static char sccsid
[] = "@(#)mountd.c 5.14 (Berkeley) 2/26/91";
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_prot.h>
* Structures for keeping the mount list and export list
struct mountlist
*ml_next
;
char ml_host
[RPCMNT_NAMELEN
+1];
char ml_dirp
[RPCMNT_PATHLEN
+1];
struct exportlist
*ex_next
;
struct exportlist
*ex_prev
;
struct grouplist
*ex_groups
;
char ex_dirp
[RPCMNT_PATHLEN
+1];
struct grouplist
*gr_next
;
int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
void add_mlist(), del_mlist(), get_exportlist(), get_mountlist();
struct exportlist exphead
;
struct mountlist
*mlhead
;
* 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
* and "-n" to allow nonroot mount.
while ((c
= getopt(argc
, argv
, "n")) != EOF
)
fprintf(stderr
, "Usage: mountd [-n] [export_file]\n");
exphead
.ex_next
= exphead
.ex_prev
= (struct exportlist
*)0;
mlhead
= (struct mountlist
*)0;
strncpy(exname
, *argv
, MAXPATHLEN
-1);
exname
[MAXPATHLEN
-1] = '\0';
strcpy(exname
, _PATH_EXPORTS
);
openlog("mountd:", LOG_PID
, LOG_DAEMON
);
signal(SIGQUIT
, SIG_IGN
);
signal(SIGHUP
, get_exportlist
);
signal(SIGTERM
, send_umntall
);
{ FILE *pidfile
= fopen(_PATH_MOUNTDPID
, "w");
fprintf(pidfile
, "%d\n", getpid());
if ((transp
= svcudp_create(RPC_ANYSOCK
)) == NULL
) {
syslog(LOG_ERR
, "Can't create socket");
pmap_unset(RPCPROG_MNT
, RPCMNT_VER1
);
if (!svc_register(transp
, RPCPROG_MNT
, RPCMNT_VER1
, mntsrv
, IPPROTO_UDP
)) {
syslog(LOG_ERR
, "Can't register mount");
syslog(LOG_ERR
, "Mountd died");
register struct svc_req
*rqstp
;
register SVCXPRT
*transp
;
register struct grouplist
*grp
;
register struct exportlist
*ep
;
struct authunix_parms
*ucr
;
char dirpath
[RPCMNT_PATHLEN
+1];
switch (rqstp
->rq_cred
.oa_flavor
) {
ucr
= (struct authunix_parms
*)rqstp
->rq_clntcred
;
saddr
= transp
->xp_raddr
.sin_addr
.s_addr
;
hp
= (struct hostent
*)0;
switch (rqstp
->rq_proc
) {
if (!svc_sendreply(transp
, xdr_void
, (caddr_t
)0))
syslog(LOG_ERR
, "Can't send reply");
if (uid
!= 0 && root_only
) {
if (!svc_getargs(transp
, xdr_dir
, dirpath
)) {
/* Check to see if it's a valid dirpath */
if (stat(dirpath
, &stb
) < 0 || (stb
.st_mode
&S_IFMT
) !=
if (!svc_sendreply(transp
, xdr_long
, (caddr_t
)&bad
))
syslog(LOG_ERR
, "Can't send reply");
/* Check in the exports list */
omask
= sigblock(sigmask(SIGHUP
));
if (!strcmp(ep
->ex_dirp
, dirpath
)) {
/* Check for a host match */
addrp
= (u_long
**)grp
->gr_hp
->h_addr_list
;
if (grp
= grp
->gr_next
) {
if (!svc_sendreply(transp
, xdr_long
, (caddr_t
)&bad
))
syslog(LOG_ERR
, "Can't send reply");
if (!svc_sendreply(transp
, xdr_long
, (caddr_t
)&bad
))
syslog(LOG_ERR
, "Can't send reply");
/* Get the file handle */
bzero((caddr_t
)&nfh
, sizeof(nfh
));
if (getfh(dirpath
, (fhandle_t
*)&nfh
) < 0) {
if (!svc_sendreply(transp
, xdr_long
, (caddr_t
)&bad
))
syslog(LOG_ERR
, "Can't send reply");
if (!svc_sendreply(transp
, xdr_fhs
, (caddr_t
)&nfh
))
syslog(LOG_ERR
, "Can't send reply");
hp
= gethostbyaddr((caddr_t
)&saddr
, sizeof(saddr
), AF_INET
);
add_mlist(hp
->h_name
, dirpath
);
if (!svc_sendreply(transp
, xdr_mlist
, (caddr_t
)0))
syslog(LOG_ERR
, "Can't send reply");
if (uid
!= 0 && root_only
) {
if (!svc_getargs(transp
, xdr_dir
, dirpath
)) {
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
);
del_mlist(hp
->h_name
, dirpath
);
if (uid
!= 0 && root_only
) {
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
);
del_mlist(hp
->h_name
, (char *)0);
if (!svc_sendreply(transp
, xdr_explist
, (caddr_t
)0))
syslog(LOG_ERR
, "Can't send reply");
* Xdr conversion for a dirpath string
return (xdr_string(xdrsp
, &dirp
, RPCMNT_PATHLEN
));
* Xdr routine to generate fhstatus
if (!xdr_long(xdrsp
, &ok
))
return (xdr_opaque(xdrsp
, (caddr_t
)nfh
, NFSX_FH
));
register struct mountlist
*mlp
;
if (!xdr_bool(xdrsp
, &true))
if (!xdr_string(xdrsp
, &strp
, RPCMNT_NAMELEN
))
if (!xdr_string(xdrsp
, &strp
, RPCMNT_PATHLEN
))
if (!xdr_bool(xdrsp
, &false))
* Xdr conversion for export list
register struct exportlist
*ep
;
register struct grouplist
*grp
;
omask
= sigblock(sigmask(SIGHUP
));
if (!xdr_bool(xdrsp
, &true))
if (!xdr_string(xdrsp
, &strp
, RPCMNT_PATHLEN
))
if (!xdr_bool(xdrsp
, &true))
strp
= grp
->gr_hp
->h_name
;
if (!xdr_string(xdrsp
, &strp
, RPCMNT_NAMELEN
))
if (!xdr_bool(xdrsp
, &false))
if (!xdr_bool(xdrsp
, &false))
register struct hostent
*hp
, *nhp
;
register char **addrp
, **naddrp
;
register struct grouplist
*grp
;
register struct exportlist
*ep
, *ep2
;
* First, get rid of the old list
* 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
);
while (fgets(line
, LINESIZ
, inf
)) {
* Get file system devno and see if an entry for this
* file system already exists.
if (stat(cp
, &sb
) < 0 || (sb
.st_mode
& S_IFMT
) != S_IFDIR
) {
"Bad Exports File, %s: %s, mountd Failed",
fep
= (struct exportlist
*)0;
if (ep
->ex_dev
== sb
.st_dev
) {
* Create new exports list entry
if (len
<= RPCMNT_PATHLEN
&& len
> 0) {
ep
= (struct exportlist
*)malloc(sizeof(*ep
));
ep
->ex_next
= ep
->ex_prev
= (struct exportlist
*)0;
ep
->ex_groups
= (struct grouplist
*)0;
bcopy(cp
, ep
->ex_dirp
, len
);
syslog(LOG_ERR
, "Bad Exports File, mountd Failed");
if (len
> RPCMNT_NAMELEN
)
do_opt(cp
+ 1, fep
, ep
, &exflags
, &rootuid
);
(hp
= gethostbyaddr((caddr_t
)&saddr
,
sizeof(saddr
), AF_INET
)) == NULL
) {
"Bad Exports File, %s: %s", cp
,
"Gethostbyaddr failed, ignored");
} else if ((hp
= gethostbyname(cp
)) == NULL
) {
syslog(LOG_ERR
, "Bad Exports File, %s: %s",
cp
, "Gethostbyname failed, ignored");
grp
= (struct grouplist
*)
malloc(sizeof(struct grouplist
));
nhp
= grp
->gr_hp
= (struct hostent
*)
malloc(sizeof(struct hostent
));
bcopy((caddr_t
)hp
, (caddr_t
)nhp
,
i
= strlen(hp
->h_name
)+1;
nhp
->h_name
= (char *)malloc(i
);
bcopy(hp
->h_name
, nhp
->h_name
, i
);
naddrp
= nhp
->h_addr_list
= (char **)
malloc(i
*sizeof(char *));
grp
->gr_next
= ep
->ex_groups
;
while (statfs(ep
->ex_dirp
, &stfsbuf
) < 0 ||
mount(MOUNT_UFS
, ep
->ex_dirp
,
stfsbuf
.f_flags
|MNT_UPDATE
, &args
) < 0) {
cp
= ep
->ex_dirp
+ dirplen
- 1;
/* back up over the last component */
while (*cp
== '/' && cp
> ep
->ex_dirp
)
while (*(cp
- 1) != '/' && cp
> ep
->ex_dirp
)
"Can't export %s", ep
->ex_dirp
);
ep
->ex_rootuid
= rootuid
;
ep
->ex_exflags
= exflags
;
ep
->ex_rootuid
= fep
->ex_rootuid
;
ep
->ex_exflags
= fep
->ex_exflags
;
ep
->ex_next
= exphead
.ex_next
;
ep
->ex_next
->ex_prev
= ep
;
syslog(LOG_ERR
, "No more memory: mountd Failed");
* Parse out the next white space separated field
while (*p
== ' ' || *p
== '\t')
if (*p
== '\n' || *p
== '\0') {
while (*p
!= ' ' && *p
!= '\t' && *p
!= '\n' && *p
!= '\0')
* Parse the option string
do_opt(cpopt
, fep
, ep
, exflagsp
, rootuidp
)
struct exportlist
*fep
, *ep
;
int *exflagsp
, *rootuidp
;
register char *cpoptarg
, *cpoptend
;
while (cpopt
&& *cpopt
) {
if (cpoptend
= index(cpopt
, ','))
if (cpoptarg
= index(cpopt
, '='))
if (!strcmp(cpopt
, "ro") || !strcmp(cpopt
, "o")) {
if (fep
&& (fep
->ex_exflags
& MNT_EXRDONLY
) == 0)
syslog(LOG_WARNING
, "ro failed for %s",
*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
, "opt %s ignored for %s", cpopt
,
#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
* Routines that maintain the remote mounttab
register struct mountlist
*mlp
, **mlpp
;
register char *eos
, *dirp
;
if (((mlfile
= fopen(_PATH_RMOUNTLIST
, "r")) == NULL
) &&
((mlfile
= fopen(_PATH_RMOUNTLIST
, "w")) == NULL
)) {
syslog(LOG_WARNING
, "Can't open %s", _PATH_RMOUNTLIST
);
while (fgets(str
, STRSIZ
, mlfile
) != NULL
) {
if ((dirp
= index(str
, '\t')) == NULL
&&
(dirp
= index(str
, ' ')) == NULL
)
mlp
= (struct mountlist
*)malloc(sizeof (*mlp
));
if (len
> RPCMNT_NAMELEN
)
bcopy(str
, mlp
->ml_host
, len
);
mlp
->ml_host
[len
] = '\0';
while (*dirp
== '\t' || *dirp
== ' ')
if ((eos
= index(dirp
, '\t')) == NULL
&&
(eos
= index(dirp
, ' ')) == NULL
&&
(eos
= index(dirp
, '\n')) == NULL
)
if (len
> RPCMNT_PATHLEN
)
bcopy(dirp
, mlp
->ml_dirp
, len
);
mlp
->ml_dirp
[len
] = '\0';
mlp
->ml_next
= (struct mountlist
*)0;
void del_mlist(hostp
, dirp
)
register char *hostp
, *dirp
;
register struct mountlist
*mlp
, **mlpp
;
if (!strcmp(mlp
->ml_host
, hostp
) &&
(!dirp
|| !strcmp(mlp
->ml_dirp
, dirp
))) {
if ((mlfile
= fopen(_PATH_RMOUNTLIST
, "w")) == NULL
) {
syslog(LOG_WARNING
, "Can't update %s", _PATH_RMOUNTLIST
);
fprintf(mlfile
, "%s %s\n", mlp
->ml_host
, mlp
->ml_dirp
);
void add_mlist(hostp
, dirp
)
register char *hostp
, *dirp
;
register struct mountlist
*mlp
, **mlpp
;
if (!strcmp(mlp
->ml_host
, hostp
) && !strcmp(mlp
->ml_dirp
, dirp
))
mlp
= (struct mountlist
*)malloc(sizeof (*mlp
));
strncpy(mlp
->ml_host
, hostp
, RPCMNT_NAMELEN
);
mlp
->ml_host
[RPCMNT_NAMELEN
] = '\0';
strncpy(mlp
->ml_dirp
, dirp
, RPCMNT_PATHLEN
);
mlp
->ml_dirp
[RPCMNT_PATHLEN
] = '\0';
mlp
->ml_next
= (struct mountlist
*)0;
if ((mlfile
= fopen(_PATH_RMOUNTLIST
, "a")) == NULL
) {
syslog(LOG_WARNING
, "Can't update %s", _PATH_RMOUNTLIST
);
fprintf(mlfile
, "%s %s\n", mlp
->ml_host
, mlp
->ml_dirp
);
* This function is called via. SIGTERM when the system is going down.
* It sends a broadcast RPCMNT_UMNTALL.
(void) clnt_broadcast(RPCPROG_MNT
, RPCMNT_VER1
, RPCMNT_UMNTALL
,
xdr_void
, (caddr_t
)0, xdr_void
, (caddr_t
)0, umntall_each
);
umntall_each(resultsp
, raddr
)
struct sockaddr_in
*raddr
;
* Free up an exports list component
register struct exportlist
*ep
;
register struct grouplist
*grp
;
addrp
= grp
->gr_hp
->h_addr_list
;
free((caddr_t
)grp
->gr_hp
->h_addr_list
);
free(grp
->gr_hp
->h_name
);
free((caddr_t
)grp
->gr_hp
);