* Copyright (c) 1989 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Herb Hasler and Rick Macklem at The University of Guelph.
* %sccs.include.redist.c%
"@(#) Copyright (c) 1989 Regents of the University of California.\n\
static char sccsid
[] = "@(#)mountd.c 5.23 (Berkeley) %G%";
#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 dirlist
*dp_right
;
struct hostlist
*dp_hosts
; /* List of hosts this dir exported to */
char dp_dirp
[1]; /* Actually malloc'd to size of dir */
struct exportlist
*ex_next
;
struct dirlist
*ex_defdir
;
struct hostent
*gt_hostent
;
struct sockaddr_iso
*gt_isoaddr
;
struct grouplist
*gr_next
;
struct grouplist
*ht_grp
;
struct hostlist
*ht_next
;
int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
void get_exportlist(), send_umntall(), nextfield(), out_of_mem();
void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp();
void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host();
void setnetgrent(), endnetgrent();
struct exportlist
*ex_search(), *get_exp();
struct grouplist
*get_grp();
char *realpath(), *add_expdir();
struct in_addr
inet_makeaddr();
struct dirlist
*dirp_search();
struct hostlist
*get_ht();
struct iso_addr
*iso_addr();
struct exportlist
*exphead
;
struct mountlist
*mlhead
;
struct grouplist
*grphead
;
struct ucred def_anon
= {
void SYSLOG
__P((int, const char *, ...));
* 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");
grphead
= (struct grouplist
*)0;
exphead
= (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
);
fprintf(stderr
,"Getting export list.\n");
fprintf(stderr
,"Getting mount list.\n");
fprintf(stderr
,"Here we go.\n");
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
,
syslog(LOG_ERR
, "Can't register mount");
syslog(LOG_ERR
, "Mountd died");
register struct svc_req
*rqstp
;
register SVCXPRT
*transp
;
register struct exportlist
*ep
;
register struct dirlist
*dp
;
struct authunix_parms
*ucr
;
char rpcpath
[RPCMNT_PATHLEN
+1], dirpath
[MAXPATHLEN
];
int bad
= ENOENT
, omask
, defset
;
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
) || uid
== -2) {
if (!svc_getargs(transp
, xdr_dir
, rpcpath
)) {
* Get the real pathname and make sure it is a directory
if (realpath(rpcpath
, dirpath
) == 0 ||
stat(dirpath
, &stb
) < 0 ||
(stb
.st_mode
& S_IFMT
) != S_IFDIR
||
statfs(dirpath
, &fsb
) < 0) {
chdir("/"); /* Just in case realpath doesn't */
fprintf(stderr
, "stat failed on %s\n", dirpath
);
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
));
ep
= ex_search(&fsb
.f_fsid
);
if (ep
&& (chk_host(ep
->ex_defdir
, saddr
, &defset
) ||
((dp
= dirp_search(ep
->ex_dirl
, dirpath
)) &&
chk_host(dp
, saddr
, &defset
)) ||
(defset
&& scan_tree(ep
->ex_defdir
, saddr
) == 0 &&
scan_tree(ep
->ex_dirl
, saddr
) == 0))) {
/* Get the file handle */
bzero((caddr_t
)&nfh
, sizeof(nfh
));
if (getfh(dirpath
, (fhandle_t
*)&nfh
) < 0) {
syslog(LOG_ERR
, "Can't get fh for %s", dirpath
);
if (!svc_sendreply(transp
, xdr_long
,
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
,
add_mlist(hp
->h_name
, dirpath
);
add_mlist(inet_ntoa(transp
->xp_raddr
.sin_addr
),
fprintf(stderr
,"Mount successfull.\n");
if (!svc_sendreply(transp
, xdr_long
, (caddr_t
)&bad
))
syslog(LOG_ERR
, "Can't send reply");
if (!svc_sendreply(transp
, xdr_mlist
, (caddr_t
)0))
syslog(LOG_ERR
, "Can't send reply");
if ((uid
!= 0 && root_only
) || uid
== -2) {
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
);
del_mlist(inet_ntoa(transp
->xp_raddr
.sin_addr
), dirpath
);
if ((uid
!= 0 && root_only
) || uid
== -2) {
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);
del_mlist(inet_ntoa(transp
->xp_raddr
.sin_addr
), (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
;
omask
= sigblock(sigmask(SIGHUP
));
if (put_exlist(ep
->ex_dirl
, xdrsp
, ep
->ex_defdir
))
if (!xdr_bool(xdrsp
, &false))
* Called from xdr_explist() to traverse the tree and export the
put_exlist(dp
, xdrsp
, adp
)
register struct dirlist
*dp
;
register struct grouplist
*grp
;
register struct hostlist
*hp
;
if (put_exlist(dp
->dp_left
, xdrsp
, adp
))
if (!xdr_bool(xdrsp
, &true))
if (!xdr_string(xdrsp
, &strp
, RPCMNT_PATHLEN
))
if (adp
&& !strcmp(dp
->dp_dirp
, adp
->dp_dirp
))
if ((dp
->dp_flag
& DP_DEFSET
) == 0 &&
(gotalldir
== 0 || (adp
->dp_flag
& DP_DEFSET
) == 0)) {
if (grp
->gr_type
== GT_HOST
) {
if (!xdr_bool(xdrsp
, &true))
strp
= grp
->gr_ptr
.gt_hostent
->h_name
;
if (!xdr_string(xdrsp
, &strp
,
} else if (grp
->gr_type
== GT_NET
) {
if (!xdr_bool(xdrsp
, &true))
strp
= grp
->gr_ptr
.gt_net
.nt_name
;
if (!xdr_string(xdrsp
, &strp
,
if (gotalldir
&& hp
== (struct hostlist
*)0) {
if (!xdr_bool(xdrsp
, &false))
if (put_exlist(dp
->dp_right
, xdrsp
, adp
))
register struct exportlist
*ep
, *ep2
;
register struct grouplist
*grp
, *tgrp
;
char *cp
, *endcp
, *dirp
, *hst
, *usr
, *dom
, savedc
;
int len
, has_host
, exflags
, got_nondir
, dirplen
, num
, i
, netgrp
;
* First, get rid of the old list
exphead
= (struct exportlist
*)0;
grphead
= (struct grouplist
*)0;
* And delete exports that are in the kernel for all local
* XXX: Should know how to handle all local exportable file systems
* instead of just MOUNT_UFS.
num
= getmntinfo(&fsp
, MNT_NOWAIT
);
for (i
= 0; i
< num
; i
++) {
if (fsp
->f_type
== MOUNT_UFS
) {
targs
.exflags
= MNT_DELEXPORT
;
if (mount(fsp
->f_type
, fsp
->f_mntonname
,
fsp
->f_flags
| MNT_UPDATE
, (caddr_t
)&targs
) < 0)
syslog(LOG_ERR
, "Can't del exports %s",
* Read in the exports file and build the list, calling
* mount() as we go along to push the export rules into the kernel.
if ((exp_file
= fopen(exname
, "r")) == NULL
) {
syslog(LOG_ERR
, "Can't open %s", exname
);
dirhead
= (struct dirlist
*)0;
fprintf(stderr
,"Got line %s\n",line
);
ep
= (struct exportlist
*)0;
* Create new exports list entry
if (len
> RPCMNT_NAMELEN
) {
if (ep
== (struct exportlist
*)0) {
fprintf(stderr
, "doing opt %s\n", cp
);
if (do_opt(&cp
, &endcp
, ep
, grp
, &has_host
,
if (stat(cp
, &sb
) >= 0 &&
(sb
.st_mode
& S_IFMT
) == S_IFDIR
&&
syslog(LOG_ERR
, "Dirs must be first");
if (ep
->ex_fs
.val
[0] != fsb
.f_fsid
.val
[0] ||
ep
->ex_fs
.val
[1] != fsb
.f_fsid
.val
[1]) {
* See if this directory is already
ep
= ex_search(&fsb
.f_fsid
);
if (ep
== (struct exportlist
*)0) {
malloc(strlen(fsb
.f_mntonname
) + 1);
"Making new ep fs=0x%x,0x%x\n",
"Found ep fs=0x%x,0x%x\n",
* Add dirpath to export mount point.
dirp
= add_expdir(&dirhead
, cp
, len
);
if (ep
== (struct exportlist
*)0) {
* Get the host or netgroup.
netgrp
= getnetgrent(&hst
, &usr
, &dom
);
grp
->gr_next
= get_grp();
if (get_host(hst
, grp
)) {
syslog(LOG_ERR
, "Bad netgroup %s", cp
);
} else if (get_host(cp
, grp
)) {
} while (netgrp
&& getnetgrent(&hst
, &usr
, &dom
));
if (check_options(dirhead
)) {
fprintf(stderr
,"Adding a default entry\n");
/* add a default group and make the grp list NULL */
hpe
= (struct hostent
*)malloc(sizeof(struct hostent
));
if (hpe
== (struct hostent
*)0)
hpe
->h_addrtype
= AF_INET
;
hpe
->h_length
= sizeof (u_long
);
hpe
->h_addr_list
= (char **)0;
grp
->gr_ptr
.gt_hostent
= hpe
;
* Don't allow a network export coincide with a list of
* host(s) on the same line.
} else if ((opt_flags
& OP_NET
) && tgrp
->gr_next
) {
* Loop through hosts, pushing the exports into the kernel.
* After loop, tgrp points to the start of the list and
* grp points to the last entry in the list.
if (do_mount(ep
, grp
, exflags
, &anon
, dirp
,
} while (grp
->gr_next
&& (grp
= grp
->gr_next
));
* Success. Update the data structures.
hang_dirp(dirhead
, tgrp
, ep
, (opt_flags
& OP_ALLDIRS
));
hang_dirp(dirhead
, (struct grouplist
*)0, ep
,
(opt_flags
& OP_ALLDIRS
));
dirhead
= (struct dirlist
*)0;
if ((ep
->ex_flag
& EX_LINKED
) == 0) {
* Insert in the list in alphabetical order.
while (ep2
&& strcmp(ep2
->ex_fsdir
, ep
->ex_fsdir
) < 0) {
ep
->ex_flag
|= EX_LINKED
;
dirhead
= (struct dirlist
*)0;
* Allocate an export list element
register struct exportlist
*ep
;
ep
= (struct exportlist
*)malloc(sizeof (struct exportlist
));
if (ep
== (struct exportlist
*)0)
bzero((caddr_t
)ep
, sizeof (struct exportlist
));
* Allocate a group list element
register struct grouplist
*gp
;
gp
= (struct grouplist
*)malloc(sizeof (struct grouplist
));
if (gp
== (struct grouplist
*)0)
bzero((caddr_t
)gp
, sizeof (struct grouplist
));
* Clean up upon an error in get_exportlist().
syslog(LOG_ERR
, "Bad exports list line %s", line
);
if (ep
&& ep
->ex_next
== (struct exportlist
*)0)
* Search the export list for a matching fs.
register struct exportlist
*ep
;
if (ep
->ex_fs
.val
[0] == fsid
->val
[0] &&
ep
->ex_fs
.val
[1] == fsid
->val
[1])
* Add a directory path to the list.
register struct dirlist
*dp
;
dp
= (struct dirlist
*)malloc(sizeof (struct dirlist
) + len
);
dp
->dp_right
= (struct dirlist
*)0;
dp
->dp_hosts
= (struct hostlist
*)0;
* Hang the dir list element off the dirpath binary tree as required
* and update the entry for host.
hang_dirp(dp
, grp
, ep
, alldirs
)
register struct dirlist
*dp
;
register struct hostlist
*hp
;
if (grp
== (struct grouplist
*)0)
ep
->ex_defdir
->dp_flag
|= DP_DEFSET
;
hp
->ht_next
= ep
->ex_defdir
->dp_hosts
;
ep
->ex_defdir
->dp_hosts
= hp
;
* Loop throught the directories adding them to the tree.
add_dlist(&ep
->ex_dirl
, dp
, grp
);
* Traverse the binary tree either updating a node that is already there
* for the new directory or adding the new node.
add_dlist(dpp
, newdp
, grp
)
register struct grouplist
*grp
;
register struct dirlist
*dp
;
register struct hostlist
*hp
;
cmp
= strcmp(dp
->dp_dirp
, newdp
->dp_dirp
);
add_dlist(&dp
->dp_left
, newdp
, grp
);
add_dlist(&dp
->dp_right
, newdp
, grp
);
dp
->dp_left
= (struct dirlist
*)0;
* Hang all of the host(s) off of the directory point.
hp
->ht_next
= dp
->dp_hosts
;
dp
->dp_flag
|= DP_DEFSET
;
* Search for a dirpath on the export point.
register struct dirlist
*dp
;
cmp
= strcmp(dp
->dp_dirp
, dirpath
);
return (dirp_search(dp
->dp_left
, dirpath
));
return (dirp_search(dp
->dp_right
, dirpath
));
* Scan for a host match in a directory tree.
chk_host(dp
, saddr
, defsetp
)
register struct hostlist
*hp
;
register struct grouplist
*grp
;
if (dp
->dp_flag
& DP_DEFSET
)
grp
->gr_ptr
.gt_hostent
->h_addr_list
;
if ((saddr
& grp
->gr_ptr
.gt_net
.nt_mask
) ==
grp
->gr_ptr
.gt_net
.nt_net
)
* Scan tree for a host that matches the address.
register struct dirlist
*dp
;
if (scan_tree(dp
->dp_left
, saddr
))
if (chk_host(dp
, saddr
, &defset
))
if (scan_tree(dp
->dp_right
, saddr
))
* Traverse the dirlist tree and free it up.
register struct dirlist
*dp
;
* Parse the option string and update fields.
* Option arguments may either be -<option>=<value> or
do_opt(cpp
, endcpp
, ep
, grp
, has_hostp
, exflagsp
, cr
)
register char *cpoptarg
, *cpoptend
;
char *cp
, *endcp
, *cpopt
, savedc
, savedc2
;
while (cpopt
&& *cpopt
) {
if (cpoptend
= index(cpopt
, ',')) {
if (cpoptarg
= index(cpopt
, '='))
if (cpoptarg
= index(cpopt
, '='))
if (endcp
> cp
&& *cp
!= '-') {
if (!strcmp(cpopt
, "ro") || !strcmp(cpopt
, "o")) {
*exflagsp
|= MNT_EXRDONLY
;
} else if (cpoptarg
&& (!strcmp(cpopt
, "maproot") ||
!(allflag
= strcmp(cpopt
, "mapall")) ||
!strcmp(cpopt
, "root") || !strcmp(cpopt
, "r"))) {
*exflagsp
|= MNT_EXPORTANON
;
} else if (!strcmp(cpopt
, "kerb") || !strcmp(cpopt
, "k")) {
} else if (cpoptarg
&& (!strcmp(cpopt
, "mask") ||
if (get_net(cpoptarg
, &grp
->gr_ptr
.gt_net
, 1)) {
syslog(LOG_ERR
, "Bad mask: %s", cpoptarg
);
} else if (cpoptarg
&& (!strcmp(cpopt
, "network") ||
if (grp
->gr_type
!= GT_NULL
) {
syslog(LOG_ERR
, "Network/host conflict");
} else if (get_net(cpoptarg
, &grp
->gr_ptr
.gt_net
, 0)) {
syslog(LOG_ERR
, "Bad net: %s", cpoptarg
);
} else if (!strcmp(cpopt
, "alldirs")) {
} else if (cpoptarg
&& !strcmp(cpopt
, "iso")) {
if (get_isoaddr(cpoptarg
, grp
)) {
syslog(LOG_ERR
, "Bad iso addr: %s", cpoptarg
);
syslog(LOG_ERR
, "Bad opt %s", cpopt
);
* Translate a character string to the corresponding list of network
* addresses for a hostname.
register struct grouplist
*grp
;
register struct hostent
*hp
, *nhp
;
register char **addrp
, **naddrp
;
if (grp
->gr_type
!= GT_NULL
)
if ((hp
= gethostbyname(cp
)) == NULL
) {
syslog(LOG_ERR
, "Inet_addr failed");
if ((hp
= gethostbyaddr((caddr_t
)&saddr
, sizeof (saddr
),
hp
->h_addrtype
= AF_INET
;
hp
->h_length
= sizeof (u_long
);
aptr
[0] = (char *)&saddr
;
syslog(LOG_ERR
, "Gethostbyname failed");
nhp
= grp
->gr_ptr
.gt_hostent
= (struct hostent
*)
malloc(sizeof(struct hostent
));
if (nhp
== (struct hostent
*)0)
bcopy((caddr_t
)hp
, (caddr_t
)nhp
,
i
= strlen(hp
->h_name
)+1;
nhp
->h_name
= (char *)malloc(i
);
if (nhp
->h_name
== (char *)0)
bcopy(hp
->h_name
, nhp
->h_name
, i
);
naddrp
= nhp
->h_addr_list
= (char **)
malloc(i
*sizeof(char *));
if (naddrp
== (char **)0)
if (*naddrp
== (char *)0)
fprintf(stderr
, "got host %s\n", hp
->h_name
);
* Free up an exports list component
register struct exportlist
*ep
;
free_host(ep
->ex_defdir
->dp_hosts
);
free((caddr_t
)ep
->ex_defdir
);
register struct hostlist
*hp
;
register struct hostlist
*hp2
;
register struct hostlist
*hp
;
hp
= (struct hostlist
*)malloc(sizeof (struct hostlist
));
if (hp
== (struct hostlist
*)0)
hp
->ht_next
= (struct hostlist
*)0;
* Translate an iso address.
struct sockaddr_iso
*isoaddr
;
if (grp
->gr_type
!= GT_NULL
)
if ((isop
= iso_addr(cp
)) == NULL
) {
"iso_addr failed, ignored");
isoaddr
= (struct sockaddr_iso
*)
malloc(sizeof (struct sockaddr_iso
));
if (isoaddr
== (struct sockaddr_iso
*)0)
bzero((caddr_t
)isoaddr
, sizeof (struct sockaddr_iso
));
bcopy((caddr_t
)isop
, (caddr_t
)&isoaddr
->siso_addr
,
sizeof (struct iso_addr
));
isoaddr
->siso_len
= sizeof (struct sockaddr_iso
);
isoaddr
->siso_family
= AF_ISO
;
grp
->gr_ptr
.gt_isoaddr
= isoaddr
;
syslog(LOG_ERR
, "Out of memory");
* Do the mount syscall with the update flag to push the export info into
do_mount(ep
, grp
, exflags
, anoncrp
, dirp
, dirplen
, fsb
)
register char *cp
= (char *)0;
struct sockaddr_in sin
, imask
;
sin
.sin_family
= AF_INET
;
sin
.sin_len
= sizeof(sin
);
imask
.sin_family
= AF_INET
;
imask
.sin_len
= sizeof(sin
);
if (grp
->gr_type
== GT_HOST
)
addrp
= (u_long
**)grp
->gr_ptr
.gt_hostent
->h_addr_list
;
sin
.sin_addr
.s_addr
= **addrp
;
sin
.sin_addr
.s_addr
= INADDR_ANY
;
args
.saddr
= (struct sockaddr
*)&sin
;
if (grp
->gr_ptr
.gt_net
.nt_mask
)
imask
.sin_addr
.s_addr
= grp
->gr_ptr
.gt_net
.nt_mask
;
net
= ntohl(grp
->gr_ptr
.gt_net
.nt_net
);
imask
.sin_addr
.s_addr
= inet_addr("255.0.0.0");
inet_addr("255.255.0.0");
inet_addr("255.255.255.0");
grp
->gr_ptr
.gt_net
.nt_mask
= imask
.sin_addr
.s_addr
;
sin
.sin_addr
.s_addr
= grp
->gr_ptr
.gt_net
.nt_net
;
args
.saddr
= (struct sockaddr
*)&sin
;
args
.slen
= sizeof (sin
);
args
.smask
= (struct sockaddr
*)&imask
;
args
.msklen
= sizeof (imask
);
args
.saddr
= (struct sockaddr
*)grp
->gr_ptr
.gt_isoaddr
;
args
.slen
= sizeof (struct sockaddr_iso
);
syslog(LOG_ERR
, "Bad grouptype");
* Maybe I should just use the fsb->f_mntonname path instead
* of looping back up the dirp to the mount point??
* Also, needs to know how to export all types of local
* exportable file systems and not just MOUNT_UFS.
while (mount(fsb
->f_type
, dirp
,
fsb
->f_flags
| MNT_UPDATE
, (caddr_t
)&args
) < 0) {
"Can't change attributes for %s.\n", dirp
);
if (opt_flags
& OP_ALLDIRS
) {
syslog(LOG_ERR
, "Not root dir");
/* back up over the last component */
while (*cp
== '/' && cp
> dirp
)
while (*(cp
- 1) != '/' && cp
> dirp
)
fprintf(stderr
,"mnt unsucc\n");
syslog(LOG_ERR
, "Can't export %s", dirp
);
if (*addrp
== (u_long
*)0)
* Translate a net address.
get_net(cp
, net
, maskflg
)
register struct netent
*np
;
struct in_addr inetaddr
, inetaddr2
;
if (np
= getnetbyname(cp
))
inetaddr
= inet_makeaddr(np
->n_net
, 0);
if ((netaddr
= inet_network(cp
)) == -1)
inetaddr
= inet_makeaddr(netaddr
, 0);
* Due to arbritrary subnet masks, you don't know how many
* bits to shift the address to make it into a network,
* however you do know how to make a network address into
* a host with host == 0 and then compare them.
while (np
= getnetent()) {
inetaddr2
= inet_makeaddr(np
->n_net
, 0);
if (inetaddr2
.s_addr
== inetaddr
.s_addr
)
net
->nt_mask
= inetaddr
.s_addr
;
name
= inet_ntoa(inetaddr
);
net
->nt_name
= (char *)malloc(strlen(name
) + 1);
if (net
->nt_name
== (char *)0)
strcpy(net
->nt_name
, name
);
net
->nt_net
= inetaddr
.s_addr
;
* 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')
* Get an exports file line. Skip over blank lines and handle line
* Loop around ignoring blank lines and getting all continuation lines.
if (fgets(p
, LINESIZ
- totlen
, exp_file
) == NULL
)
(*cp
== ' ' || *cp
== '\t' || *cp
== '\n' || *cp
== '\\')) {
syslog(LOG_ERR
, "Exports line too long");
} while (totlen
== 0 || cont_line
);
* Parse a description of a credential.
register struct ucred
*cr
;
int ngroups
, groups
[NGROUPS
+ 1];
* Set up the unpriviledged user.
* Get the user's password table entry.
names
= strsep(&namelist
, " \t\n");
name
= strsep(&names
, ":");
if (isdigit(*name
) || *name
== '-')
pw
= getpwuid(atoi(name
));
* Credentials specified as those of a user.
syslog(LOG_ERR
, "Unknown user: %s\n", name
);
if (getgrouplist(pw
->pw_name
, pw
->pw_gid
, groups
, &ngroups
))
syslog(LOG_ERR
, "Too many groups\n");
* Convert from int's to gid_t's and compress out duplicate
cr
->cr_ngroups
= ngroups
- 1;
cr
->cr_groups
[0] = groups
[0];
for (cnt
= 2; cnt
< ngroups
; cnt
++)
cr
->cr_groups
[cnt
- 1] = groups
[cnt
];
* Explicit credential specified as a colon separated list:
else if (isdigit(*name
) || *name
== '-')
syslog(LOG_ERR
, "Unknown user: %s\n", name
);
while (names
!= NULL
&& *names
!= '\0' && cr
->cr_ngroups
< NGROUPS
) {
name
= strsep(&names
, ":");
if (isdigit(*name
) || *name
== '-') {
cr
->cr_groups
[cr
->cr_ngroups
++] = atoi(name
);
if ((gr
= getgrnam(name
)) == NULL
) {
syslog(LOG_ERR
, "Unknown group: %s\n", name
);
cr
->cr_groups
[cr
->cr_ngroups
++] = gr
->gr_gid
;
if (names
!= NULL
&& *names
!= '\0' && cr
->cr_ngroups
== NGROUPS
)
syslog(LOG_ERR
, "Too many groups\n");
#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
) {
syslog(LOG_ERR
, "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;
register char *hostp
, *dirp
;
register struct mountlist
*mlp
, **mlpp
;
if (!strcmp(mlp
->ml_host
, hostp
) &&
(!dirp
|| !strcmp(mlp
->ml_dirp
, dirp
))) {
*mlpp
= mlp
= mlp
->ml_next
;
if ((mlfile
= fopen(_PATH_RMOUNTLIST
, "w")) == NULL
) {
syslog(LOG_ERR
,"Can't update %s", _PATH_RMOUNTLIST
);
fprintf(mlfile
, "%s %s\n", mlp
->ml_host
, mlp
->ml_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_ERR
, "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
;
register struct grouplist
*grp
;
if (grp
->gr_type
== GT_HOST
) {
if (grp
->gr_ptr
.gt_hostent
->h_name
) {
addrp
= grp
->gr_ptr
.gt_hostent
->h_addr_list
;
free((caddr_t
)grp
->gr_ptr
.gt_hostent
->h_addr_list
);
free(grp
->gr_ptr
.gt_hostent
->h_name
);
free((caddr_t
)grp
->gr_ptr
.gt_hostent
);
} else if (grp
->gr_type
== GT_NET
) {
if (grp
->gr_ptr
.gt_net
.nt_name
)
free(grp
->gr_ptr
.gt_net
.nt_name
);
else if (grp
->gr_type
== GT_ISO
)
free((caddr_t
)grp
->gr_ptr
.gt_isoaddr
);
* char *realpath(const char *path, char resolved_path[MAXPATHLEN])
* find the real name of path, by removing all ".", ".."
* and symlink components.
* Jan-Simon Pendry, September 1991.
char resolved
[MAXPATHLEN
];
int d
= open(".", O_RDONLY
);
q
= strrchr(resolved
, '/');
while (q
> resolved
&& *q
== '/');
if (lstat(p
, &stb
) == 0) {
if (S_ISLNK(stb
.st_mode
)) {
int n
= readlink(p
, resolved
, MAXPATHLEN
);
if (S_ISDIR(stb
.st_mode
)) {
if (getcwd(resolved
, MAXPATHLEN
) == 0)
if (resolved
[0] == '/' && resolved
[1] == '\0')
if (strlen(resolved
) + strlen(wbuf
) + rootd
+ 1 > MAXPATHLEN
) {
SYSLOG(int pri
, const char *fmt
, ...)
vfprintf(stderr
, fmt
, ap
);
* Check options for consistency.
if (dp
== (struct dirlist
*)0)
if ((opt_flags
& (OP_MAPROOT
| OP_MAPALL
)) == (OP_MAPROOT
| OP_MAPALL
) ||
(opt_flags
& (OP_MAPROOT
| OP_KERB
)) == (OP_MAPROOT
| OP_KERB
) ||
(opt_flags
& (OP_MAPALL
| OP_KERB
)) == (OP_MAPALL
| OP_KERB
)) {
syslog(LOG_ERR
, "-mapall, -maproot and -kerb mutually exclusive");
if ((opt_flags
& OP_MASK
) && (opt_flags
& OP_NET
) == 0) {
syslog(LOG_ERR
, "-mask requires -net");
if ((opt_flags
& (OP_NET
| OP_ISO
)) == (OP_NET
| OP_ISO
)) {
syslog(LOG_ERR
, "-net and -iso mutually exclusive");
if ((opt_flags
& OP_ALLDIRS
) && dp
->dp_left
) {
syslog(LOG_ERR
, "-alldir has multiple directories");