diff options
Diffstat (limited to 'sbin/mountd')
-rw-r--r-- | sbin/mountd/Makefile | 10 | ||||
-rw-r--r-- | sbin/mountd/exports.5 | 250 | ||||
-rw-r--r-- | sbin/mountd/mountd.8 | 100 | ||||
-rw-r--r-- | sbin/mountd/mountd.c | 2005 | ||||
-rw-r--r-- | sbin/mountd/netgroup.5 | 91 | ||||
-rw-r--r-- | sbin/mountd/pathnames.h | 39 |
6 files changed, 2495 insertions, 0 deletions
diff --git a/sbin/mountd/Makefile b/sbin/mountd/Makefile new file mode 100644 index 0000000..36e2a05 --- /dev/null +++ b/sbin/mountd/Makefile @@ -0,0 +1,10 @@ +# @(#)Makefile 8.3 (Berkeley) 1/25/94 + +PROG= mountd +CFLAGS+=-DNFS -DMFS -DCD9660 +MAN5= exports.0 netgroup.0 +MAN8= mountd.0 +DPADD= ${LIBRPC} +LDADD= -lrpc + +.include <bsd.prog.mk> diff --git a/sbin/mountd/exports.5 b/sbin/mountd/exports.5 new file mode 100644 index 0000000..d32527f --- /dev/null +++ b/sbin/mountd/exports.5 @@ -0,0 +1,250 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" 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. +.\" +.\" @(#)exports.5 8.2 (Berkeley) 1/28/94 +.\" +.Dd January 28, 1994 +.Dt EXPORTS 5 +.Os +.Sh NAME +.Nm exports +.Nd define remote mount points for +.Tn NFS +mount requests +.Sh SYNOPSIS +.Nm exports +.Sh DESCRIPTION +The +.Nm exports +file specifies remote mount points for the +.Tn NFS +mount protocol per the +.Tn NFS +server specification; see +.%T "Network File System Protocol Specification \\*(tNRFC\\*(sP 1094, Appendix A" . +.Pp +Each line in the file +(other than comment lines that begin with a #) +specifies the mount point(s) and export flags within one local server +filesystem for one or more hosts. +A host may be specified only once for each local filesystem on the +server and there may be only one default entry for each server +filesystem that applies to all other hosts. +The latter exports the filesystem to the ``world'' and should +be used only when the filesystem contains public information. +.Pp +In a mount entry, +the first field(s) specify the directory path(s) within a server filesystem +that can be mounted on by the corresponding client(s). +There are two forms of this specification. +The first is to list all mount points as absolute +directory paths separated by whitespace. +The second is to specify the pathname of the root of the filesystem +followed by the +.Fl alldirs +flag; +this form allows the host(s) to mount any directory within the filesystem. +The pathnames must not have any symbolic links in them and should not have +any "." or ".." components. +Mount points for a filesystem may appear on multiple lines each with +different sets of hosts and export options. +.Pp +The second component of a line specifies how the filesystem is to be +exported to the host set. +The option flags specify whether the filesystem +is exported read-only or read-write and how the client uid is mapped to +user credentials on the server. +.Pp +Export options are specified as follows: +.Pp +.Sm off +.Fl maproot No = Sy user +.Sm on +The credential of the specified user is used for remote access by root. +The credential includes all the groups to which the user is a member +on the local machine (see +.Xr id 1 ). +The user may be specified by name or number. +.Pp +.Sm off +.Fl maproot No = Sy user:group1:group2:... +.Sm on +The colon separated list is used to specify the precise credential +to be used for remote access by root. +The elements of the list may be either names or numbers. +Note that user: should be used to distinguish a credential containing +no groups from a complete credential for that user. +.Pp +.Sm off +.Fl mapall No = Sy user +.Sm on +or +.Sm off +.Fl mapall No = Sy user:group1:group2:... +.Sm on +specifies a mapping for all client uids (including root) +using the same semantics as +.Fl maproot . +.Pp +The option +.Fl r +is a synonym for +.Fl maproot +in an effort to be backward compatible with older export file formats. +.Pp +In the absence of +.Fl maproot +and +.Fl mapall +options, remote accesses by root will result in using a credential of -2:-2. +All other users will be mapped to their remote credential. +If a +.Fl maproot +option is given, +remote access by root will be mapped to that credential instead of -2:-2. +If a +.Fl mapall +option is given, +all users (including root) will be mapped to that credential in +place of their own. +.Pp +The +.Fl kerb +option specifies that the Kerberos authentication server should be +used to authenticate and map client credentials. +(Note that this is NOT Sun NFS compatible and +is supported for TCP transport only.) +.Pp +The +.Fl ro +option specifies that the filesystem should be exported read-only +(default read/write). +The option +.Fl o +is a synonym for +.Fl ro +in an effort to be backward compatible with older export file formats. +.Pp +The third component of a line specifies the host set to which the line applies. +The set may be specified in three ways. +The first way is to list the host name(s) separated by white space. +(Standard internet ``dot'' addresses may be used in place of names.) +The second way is to specify a ``netgroup'' as defined in the netgroup file (see +.Xr netgroup 5 ). +The third way is to specify an internet subnetwork using a network and +network mask that is defined as the set of all hosts with addresses within +the subnetwork. +This latter approach requires less overhead within the +kernel and is recommended for cases where the export line refers to a +large number of clients within an administrative subnet. +.Pp +The first two cases are specified by simply listing the name(s) separated +by whitespace. +All names are checked to see if they are ``netgroup'' names +first and are assumed to be hostnames otherwise. +Using the full domain specification for a hostname can normally +circumvent the problem of a host that has the same name as a netgroup. +The third case is specified by the flag +.Sm off +.Fl network No = Sy netname +.Sm on +and optionally +.Sm off +.Fl mask No = Sy netmask . +.Sm on +If the mask is not specified, it will default to the mask for that network +class (A, B or C; see +.Xr inet 5 ). +.Pp +For example: +.Bd -literal -offset indent +/usr /usr/local -maproot=0:10 friends +/usr -maproot=daemon grumpy.cis.uoguelph.ca 131.104.48.16 +/usr -ro -mapall=nobody +/u -maproot=bin: -network 131.104.48 -mask 255.255.255.0 +/u2 -maproot=root friends +/u2 -alldirs -kerb -network cis-net -mask cis-mask +.Ed +.Pp +Given that +.Sy /usr , +.Sy /u +and +.Sy /u2 +are +local filesystem mount points, the above example specifies the following: +.Sy /usr +is exported to hosts +.Em friends +where friends is specified in the netgroup file +with users mapped to their remote credentials and +root mapped to uid 0 and group 10. +It is exported read-write and the hosts in ``friends'' can mount either /usr +or /usr/local. +It is exported to +.Em 131.104.48.16 +and +.Em grumpy.cis.uoguelph.ca +with users mapped to their remote credentials and +root mapped to the user and groups associated with ``daemon''; +it is exported to the rest of the world as read-only with +all users mapped to the user and groups associated with ``nobody''. +.Pp +.Sy /u +is exported to all hosts on the subnetwork +.Em 131.104.48 +with root mapped to the uid for ``bin'' and with no group access. +.Pp +.Sy /u2 +is exported to the hosts in ``friends'' with root mapped to uid and groups +associated with ``root''; +it is exported to all hosts on network ``cis-net'' allowing mounts at any +directory within /u2 and mapping all uids to credentials for the principal +that is authenticated by a Kerberos ticket. +.Sh FILES +.Bl -tag -width /etc/exports -compact +.It Pa /etc/exports +The default remote mount-point file. +.El +.Sh SEE ALSO +.Xr netgroup 5 , +.Xr mountd 8 , +.Xr nfsd 8 , +.Xr showmount 8 +.Sh BUGS +The export options are tied to the local mount points in the kernel and +must be non-contradictory for any exported subdirectory of the local +server mount point. +It is recommended that all exported directories within the same server +filesystem be specified on adjacent lines going down the tree. +You cannot specify a hostname that is also the name of a netgroup. +Specifying the full domain specification for a hostname can normally +circumvent the problem. diff --git a/sbin/mountd/mountd.8 b/sbin/mountd/mountd.8 new file mode 100644 index 0000000..47a6cfc --- /dev/null +++ b/sbin/mountd/mountd.8 @@ -0,0 +1,100 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" 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. +.\" +.\" @(#)mountd.8 8.1 (Berkeley) 6/9/93 +.\" +.Dd June 9, 1993 +.Dt MOUNTD 8 +.Os +.Sh NAME +.Nm mountd +.Nd service remote +.Tn NFS +mount requests +.Sh SYNOPSIS +.Nm /sbin/mountd +.Op Fl n +.Op Ar exportsfile +.Sh DESCRIPTION +.Xr Mountd +is the server for +.Tn NFS +mount requests from other client machines. +.Xr Mountd +listens for service requests at the port indicated in the +.Tn NFS +server specification; see +.%T "Network File System Protocol Specification" , +RFC1094. +.Pp +Options and operands available for +.Nm mountd : +.Bl -tag -width Ds +.It Fl n +The +.Fl n +option allows non-root mount requests to be served. +This should only be specified if there are clients such as PC's, +that require it. +.It Ar exportsfile +The +.Ar exportsfile +argument specifies an alternate location +for the exports file. +.El +.Pp +When mountd is started, +it loads the export host addresses and options into the kernel +using the mount(2) system call. +After changing the exports file, +a hangup signal should be sent to the mountd daemon +to get it to reload the export information. +After sending the SIGHUP +(kill -HUP `cat /var/run/mountd.pid`), +check the syslog output to see if mountd logged any parsing +errors in the exports file. +.Sh FILES +.Bl -tag -width /var/run/mountd.pid -compact +.It Pa /etc/exports +the list of exported filesystems +.It Pa /var/run/mountd.pid +the pid of the currently running mountd +.El +.Sh SEE ALSO +.Xr nfsstat 1 , +.Xr exports 5 , +.Xr nfsd 8 , +.Xr portmap 8 , +.Xr showmount 8 +.Sh HISTORY +The +.Nm mountd +utility first appeared in 4.4BSD. diff --git a/sbin/mountd/mountd.c b/sbin/mountd/mountd.c new file mode 100644 index 0000000..d7c31df --- /dev/null +++ b/sbin/mountd/mountd.c @@ -0,0 +1,2005 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Herb Hasler and 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 +static char copyright[] = +"@(#) Copyright (c) 1989, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif not lint + +#ifndef lint +static char sccsid[] = "@(#)mountd.c 8.8 (Berkeley) 2/20/94"; +#endif not lint + +#include <sys/param.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/mount.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/syslog.h> +#include <sys/ucred.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <rpc/pmap_prot.h> +#ifdef ISO +#include <netiso/iso.h> +#endif +#include <nfs/rpcv2.h> +#include <nfs/nfsv2.h> + +#include <arpa/inet.h> + +#include <ctype.h> +#include <errno.h> +#include <grp.h> +#include <netdb.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "pathnames.h" + +#ifdef DEBUG +#include <stdarg.h> +#endif + +/* + * Structures for keeping the mount list and export list + */ +struct mountlist { + struct mountlist *ml_next; + char ml_host[RPCMNT_NAMELEN+1]; + char ml_dirp[RPCMNT_PATHLEN+1]; +}; + +struct dirlist { + struct dirlist *dp_left; + struct dirlist *dp_right; + int dp_flag; + struct hostlist *dp_hosts; /* List of hosts this dir exported to */ + char dp_dirp[1]; /* Actually malloc'd to size of dir */ +}; +/* dp_flag bits */ +#define DP_DEFSET 0x1 + +struct exportlist { + struct exportlist *ex_next; + struct dirlist *ex_dirl; + struct dirlist *ex_defdir; + int ex_flag; + fsid_t ex_fs; + char *ex_fsdir; +}; +/* ex_flag bits */ +#define EX_LINKED 0x1 + +struct netmsk { + u_long nt_net; + u_long nt_mask; + char *nt_name; +}; + +union grouptypes { + struct hostent *gt_hostent; + struct netmsk gt_net; +#ifdef ISO + struct sockaddr_iso *gt_isoaddr; +#endif +}; + +struct grouplist { + int gr_type; + union grouptypes gr_ptr; + struct grouplist *gr_next; +}; +/* Group types */ +#define GT_NULL 0x0 +#define GT_HOST 0x1 +#define GT_NET 0x2 +#define GT_ISO 0x4 + +struct hostlist { + struct grouplist *ht_grp; + struct hostlist *ht_next; +}; + +/* Global defs */ +char *add_expdir __P((struct dirlist **, char *, int)); +void add_dlist __P((struct dirlist **, struct dirlist *, + struct grouplist *)); +void add_mlist __P((char *, char *)); +int check_dirpath __P((char *)); +int check_options __P((struct dirlist *)); +int chk_host __P((struct dirlist *, u_long, int *)); +void del_mlist __P((char *, char *)); +struct dirlist *dirp_search __P((struct dirlist *, char *)); +int do_mount __P((struct exportlist *, struct grouplist *, int, + struct ucred *, char *, int, struct statfs *)); +int do_opt __P((char **, char **, struct exportlist *, struct grouplist *, + int *, int *, struct ucred *)); +struct exportlist *ex_search __P((fsid_t *)); +struct exportlist *get_exp __P((void)); +void free_dir __P((struct dirlist *)); +void free_exp __P((struct exportlist *)); +void free_grp __P((struct grouplist *)); +void free_host __P((struct hostlist *)); +void get_exportlist __P((void)); +int get_host __P((char *, struct grouplist *)); +struct hostlist *get_ht __P((void)); +int get_line __P((void)); +void get_mountlist __P((void)); +int get_net __P((char *, struct netmsk *, int)); +void getexp_err __P((struct exportlist *, struct grouplist *)); +struct grouplist *get_grp __P((void)); +void hang_dirp __P((struct dirlist *, struct grouplist *, + struct exportlist *, int)); +void mntsrv __P((struct svc_req *, SVCXPRT *)); +void nextfield __P((char **, char **)); +void out_of_mem __P((void)); +void parsecred __P((char *, struct ucred *)); +int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); +int scan_tree __P((struct dirlist *, u_long)); +void send_umntall __P((void)); +int umntall_each __P((caddr_t, struct sockaddr_in *)); +int xdr_dir __P((XDR *, char *)); +int xdr_explist __P((XDR *, caddr_t)); +int xdr_fhs __P((XDR *, nfsv2fh_t *)); +int xdr_mlist __P((XDR *, caddr_t)); + +/* C library */ +int getnetgrent(); +void endnetgrent(); +void setnetgrent(); + +#ifdef ISO +struct iso_addr *iso_addr(); +#endif + +struct exportlist *exphead; +struct mountlist *mlhead; +struct grouplist *grphead; +char exname[MAXPATHLEN]; +struct ucred def_anon = { + 1, + (uid_t) -2, + 1, + { (gid_t) -2 } +}; +int root_only = 1; +int opt_flags; +/* Bits for above */ +#define OP_MAPROOT 0x01 +#define OP_MAPALL 0x02 +#define OP_KERB 0x04 +#define OP_MASK 0x08 +#define OP_NET 0x10 +#define OP_ISO 0x20 +#define OP_ALLDIRS 0x40 + +#ifdef DEBUG +int debug = 1; +void SYSLOG __P((int, const char *, ...)); +#define syslog SYSLOG +#else +int debug = 0; +#endif + +/* + * 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. + */ +int +main(argc, argv) + int argc; + char **argv; +{ + SVCXPRT *transp; + int c; + + 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; + grphead = (struct grouplist *)NULL; + exphead = (struct exportlist *)NULL; + mlhead = (struct mountlist *)NULL; + if (argc == 1) { + strncpy(exname, *argv, MAXPATHLEN-1); + exname[MAXPATHLEN-1] = '\0'; + } else + strcpy(exname, _PATH_EXPORTS); + openlog("mountd", LOG_PID, LOG_DAEMON); + if (debug) + fprintf(stderr,"Getting export list.\n"); + get_exportlist(); + if (debug) + fprintf(stderr,"Getting mount list.\n"); + get_mountlist(); + if (debug) + fprintf(stderr,"Here we go.\n"); + if (debug == 0) { + daemon(0, 0); + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + } + signal(SIGHUP, (void (*) __P((int))) get_exportlist); + signal(SIGTERM, (void (*) __P((int))) send_umntall); + { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); + if (pidfile != NULL) { + fprintf(pidfile, "%d\n", getpid()); + fclose(pidfile); + } + } + if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { + syslog(LOG_ERR, "Can't create socket"); + exit(1); + } + pmap_unset(RPCPROG_MNT, RPCMNT_VER1); + if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, + IPPROTO_UDP)) { + syslog(LOG_ERR, "Can't register mount"); + exit(1); + } + svc_run(); + syslog(LOG_ERR, "Mountd died"); + exit(1); +} + +/* + * The mount rpc service + */ +void +mntsrv(rqstp, transp) + struct svc_req *rqstp; + SVCXPRT *transp; +{ + struct exportlist *ep; + struct dirlist *dp; + nfsv2fh_t nfh; + struct authunix_parms *ucr; + struct stat stb; + struct statfs fsb; + struct hostent *hp; + u_long saddr; + char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; + int bad = ENOENT, omask, defset; + 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 *)NULL; + switch (rqstp->rq_proc) { + case NULLPROC: + if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) + syslog(LOG_ERR, "Can't send reply"); + return; + case RPCMNT_MOUNT: + if ((uid != 0 && root_only) || uid == -2) { + svcerr_weakauth(transp); + return; + } + if (!svc_getargs(transp, xdr_dir, rpcpath)) { + svcerr_decode(transp); + return; + } + + /* + * Get the real pathname and make sure it is a directory + * that exists. + */ + 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 */ + if (debug) + fprintf(stderr, "stat failed on %s\n", dirpath); + 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 = ex_search(&fsb.f_fsid); + defset = 0; + 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) { + bad = errno; + syslog(LOG_ERR, "Can't get fh for %s", dirpath); + if (!svc_sendreply(transp, xdr_long, + (caddr_t)&bad)) + syslog(LOG_ERR, "Can't send reply"); + sigsetmask(omask); + 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); + else + add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), + dirpath); + if (debug) + fprintf(stderr,"Mount successfull.\n"); + } else { + bad = EACCES; + if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) + syslog(LOG_ERR, "Can't send reply"); + } + sigsetmask(omask); + return; + case RPCMNT_DUMP: + if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) + syslog(LOG_ERR, "Can't send reply"); + return; + case RPCMNT_UMOUNT: + if ((uid != 0 && root_only) || uid == -2) { + svcerr_weakauth(transp); + return; + } + if (!svc_getargs(transp, xdr_dir, dirpath)) { + svcerr_decode(transp); + return; + } + if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) + syslog(LOG_ERR, "Can't send reply"); + hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); + if (hp) + del_mlist(hp->h_name, dirpath); + del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); + return; + case RPCMNT_UMNTALL: + if ((uid != 0 && root_only) || uid == -2) { + svcerr_weakauth(transp); + return; + } + if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) + syslog(LOG_ERR, "Can't send reply"); + hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); + if (hp) + del_mlist(hp->h_name, (char *)NULL); + del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); + return; + case RPCMNT_EXPORT: + if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) + syslog(LOG_ERR, "Can't send reply"); + return; + default: + svcerr_noproc(transp); + return; + } +} + +/* + * Xdr conversion for a dirpath string + */ +int +xdr_dir(xdrsp, dirp) + XDR *xdrsp; + char *dirp; +{ + return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); +} + +/* + * Xdr routine to generate fhstatus + */ +int +xdr_fhs(xdrsp, nfh) + XDR *xdrsp; + nfsv2fh_t *nfh; +{ + int ok = 0; + + if (!xdr_long(xdrsp, &ok)) + return (0); + return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); +} + +int +xdr_mlist(xdrsp, cp) + XDR *xdrsp; + caddr_t cp; +{ + 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, RPCMNT_NAMELEN)) + return (0); + strp = &mlp->ml_dirp[0]; + if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) + return (0); + mlp = mlp->ml_next; + } + if (!xdr_bool(xdrsp, &false)) + return (0); + return (1); +} + +/* + * Xdr conversion for export list + */ +int +xdr_explist(xdrsp, cp) + XDR *xdrsp; + caddr_t cp; +{ + struct exportlist *ep; + int false = 0; + int omask, putdef; + + omask = sigblock(sigmask(SIGHUP)); + ep = exphead; + while (ep) { + putdef = 0; + if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) + goto errout; + if (ep->ex_defdir && putdef == 0 && + put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, + &putdef)) + goto errout; + ep = ep->ex_next; + } + sigsetmask(omask); + if (!xdr_bool(xdrsp, &false)) + return (0); + return (1); +errout: + sigsetmask(omask); + return (0); +} + +/* + * Called from xdr_explist() to traverse the tree and export the + * directory paths. + */ +int +put_exlist(dp, xdrsp, adp, putdefp) + struct dirlist *dp; + XDR *xdrsp; + struct dirlist *adp; + int *putdefp; +{ + struct grouplist *grp; + struct hostlist *hp; + int true = 1; + int false = 0; + int gotalldir = 0; + char *strp; + + if (dp) { + if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) + return (1); + if (!xdr_bool(xdrsp, &true)) + return (1); + strp = dp->dp_dirp; + if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) + return (1); + if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { + gotalldir = 1; + *putdefp = 1; + } + if ((dp->dp_flag & DP_DEFSET) == 0 && + (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { + hp = dp->dp_hosts; + while (hp) { + grp = hp->ht_grp; + if (grp->gr_type == GT_HOST) { + if (!xdr_bool(xdrsp, &true)) + return (1); + strp = grp->gr_ptr.gt_hostent->h_name; + if (!xdr_string(xdrsp, &strp, + RPCMNT_NAMELEN)) + return (1); + } else if (grp->gr_type == GT_NET) { + if (!xdr_bool(xdrsp, &true)) + return (1); + strp = grp->gr_ptr.gt_net.nt_name; + if (!xdr_string(xdrsp, &strp, + RPCMNT_NAMELEN)) + return (1); + } + hp = hp->ht_next; + if (gotalldir && hp == (struct hostlist *)NULL) { + hp = adp->dp_hosts; + gotalldir = 0; + } + } + } + if (!xdr_bool(xdrsp, &false)) + return (1); + if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) + return (1); + } + return (0); +} + +#define LINESIZ 10240 +char line[LINESIZ]; +FILE *exp_file; + +/* + * Get the export list + */ +void +get_exportlist() +{ + struct exportlist *ep, *ep2; + struct grouplist *grp, *tgrp; + struct exportlist **epp; + struct dirlist *dirhead; + struct statfs fsb, *fsp; + struct hostent *hpe; + struct ucred anon; + 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 + */ + ep = exphead; + while (ep) { + ep2 = ep; + ep = ep->ex_next; + free_exp(ep2); + } + exphead = (struct exportlist *)NULL; + + grp = grphead; + while (grp) { + tgrp = grp; + grp = grp->gr_next; + free_grp(tgrp); + } + grphead = (struct grouplist *)NULL; + + /* + * And delete exports that are in the kernel for all local + * file systems. + * 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++) { + union { + struct ufs_args ua; + struct iso_args ia; + struct mfs_args ma; + } targs; + + switch (fsp->f_type) { + case MOUNT_MFS: + case MOUNT_UFS: + case MOUNT_CD9660: + targs.ua.fspec = NULL; + targs.ua.export.ex_flags = MNT_DELEXPORT; + if (mount(fsp->f_type, fsp->f_mntonname, + fsp->f_flags | MNT_UPDATE, + (caddr_t)&targs) < 0) + syslog(LOG_ERR, "Can't delete exports for %s", + fsp->f_mntonname); + } + fsp++; + } + + /* + * 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); + exit(2); + } + dirhead = (struct dirlist *)NULL; + while (get_line()) { + if (debug) + fprintf(stderr,"Got line %s\n",line); + cp = line; + nextfield(&cp, &endcp); + if (*cp == '#') + goto nextline; + + /* + * Set defaults. + */ + has_host = FALSE; + anon = def_anon; + exflags = MNT_EXPORTED; + got_nondir = 0; + opt_flags = 0; + ep = (struct exportlist *)NULL; + + /* + * Create new exports list entry + */ + len = endcp-cp; + tgrp = grp = get_grp(); + while (len > 0) { + if (len > RPCMNT_NAMELEN) { + getexp_err(ep, tgrp); + goto nextline; + } + if (*cp == '-') { + if (ep == (struct exportlist *)NULL) { + getexp_err(ep, tgrp); + goto nextline; + } + if (debug) + fprintf(stderr, "doing opt %s\n", cp); + got_nondir = 1; + if (do_opt(&cp, &endcp, ep, grp, &has_host, + &exflags, &anon)) { + getexp_err(ep, tgrp); + goto nextline; + } + } else if (*cp == '/') { + savedc = *endcp; + *endcp = '\0'; + if (check_dirpath(cp) && + statfs(cp, &fsb) >= 0) { + if (got_nondir) { + syslog(LOG_ERR, "Dirs must be first"); + getexp_err(ep, tgrp); + goto nextline; + } + if (ep) { + if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || + ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { + getexp_err(ep, tgrp); + goto nextline; + } + } else { + /* + * See if this directory is already + * in the list. + */ + ep = ex_search(&fsb.f_fsid); + if (ep == (struct exportlist *)NULL) { + ep = get_exp(); + ep->ex_fs = fsb.f_fsid; + ep->ex_fsdir = (char *) + malloc(strlen(fsb.f_mntonname) + 1); + if (ep->ex_fsdir) + strcpy(ep->ex_fsdir, + fsb.f_mntonname); + else + out_of_mem(); + if (debug) + fprintf(stderr, + "Making new ep fs=0x%x,0x%x\n", + fsb.f_fsid.val[0], + fsb.f_fsid.val[1]); + } else if (debug) + fprintf(stderr, + "Found ep fs=0x%x,0x%x\n", + fsb.f_fsid.val[0], + fsb.f_fsid.val[1]); + } + + /* + * Add dirpath to export mount point. + */ + dirp = add_expdir(&dirhead, cp, len); + dirplen = len; + } else { + getexp_err(ep, tgrp); + goto nextline; + } + *endcp = savedc; + } else { + savedc = *endcp; + *endcp = '\0'; + got_nondir = 1; + if (ep == (struct exportlist *)NULL) { + getexp_err(ep, tgrp); + goto nextline; + } + + /* + * Get the host or netgroup. + */ + setnetgrent(cp); + netgrp = getnetgrent(&hst, &usr, &dom); + do { + if (has_host) { + grp->gr_next = get_grp(); + grp = grp->gr_next; + } + if (netgrp) { + if (get_host(hst, grp)) { + syslog(LOG_ERR, "Bad netgroup %s", cp); + getexp_err(ep, tgrp); + goto nextline; + } + } else if (get_host(cp, grp)) { + getexp_err(ep, tgrp); + goto nextline; + } + has_host = TRUE; + } while (netgrp && getnetgrent(&hst, &usr, &dom)); + endnetgrent(); + *endcp = savedc; + } + cp = endcp; + nextfield(&cp, &endcp); + len = endcp - cp; + } + if (check_options(dirhead)) { + getexp_err(ep, tgrp); + goto nextline; + } + if (!has_host) { + grp->gr_type = GT_HOST; + if (debug) + 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 *)NULL) + out_of_mem(); + hpe->h_name = "Default"; + hpe->h_addrtype = AF_INET; + hpe->h_length = sizeof (u_long); + hpe->h_addr_list = (char **)NULL; + 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) { + getexp_err(ep, tgrp); + goto nextline; + } + + /* + * 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. + */ + grp = tgrp; + do { + if (do_mount(ep, grp, exflags, &anon, dirp, + dirplen, &fsb)) { + getexp_err(ep, tgrp); + goto nextline; + } + } while (grp->gr_next && (grp = grp->gr_next)); + + /* + * Success. Update the data structures. + */ + if (has_host) { + hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); + grp->gr_next = grphead; + grphead = tgrp; + } else { + hang_dirp(dirhead, (struct grouplist *)NULL, ep, + (opt_flags & OP_ALLDIRS)); + free_grp(grp); + } + dirhead = (struct dirlist *)NULL; + if ((ep->ex_flag & EX_LINKED) == 0) { + ep2 = exphead; + epp = &exphead; + + /* + * Insert in the list in alphabetical order. + */ + while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { + epp = &ep2->ex_next; + ep2 = ep2->ex_next; + } + if (ep2) + ep->ex_next = ep2; + *epp = ep; + ep->ex_flag |= EX_LINKED; + } +nextline: + if (dirhead) { + free_dir(dirhead); + dirhead = (struct dirlist *)NULL; + } + } + fclose(exp_file); +} + +/* + * Allocate an export list element + */ +struct exportlist * +get_exp() +{ + struct exportlist *ep; + + ep = (struct exportlist *)malloc(sizeof (struct exportlist)); + if (ep == (struct exportlist *)NULL) + out_of_mem(); + bzero((caddr_t)ep, sizeof (struct exportlist)); + return (ep); +} + +/* + * Allocate a group list element + */ +struct grouplist * +get_grp() +{ + struct grouplist *gp; + + gp = (struct grouplist *)malloc(sizeof (struct grouplist)); + if (gp == (struct grouplist *)NULL) + out_of_mem(); + bzero((caddr_t)gp, sizeof (struct grouplist)); + return (gp); +} + +/* + * Clean up upon an error in get_exportlist(). + */ +void +getexp_err(ep, grp) + struct exportlist *ep; + struct grouplist *grp; +{ + struct grouplist *tgrp; + + syslog(LOG_ERR, "Bad exports list line %s", line); + if (ep && (ep->ex_flag & EX_LINKED) == 0) + free_exp(ep); + while (grp) { + tgrp = grp; + grp = grp->gr_next; + free_grp(tgrp); + } +} + +/* + * Search the export list for a matching fs. + */ +struct exportlist * +ex_search(fsid) + fsid_t *fsid; +{ + struct exportlist *ep; + + ep = exphead; + while (ep) { + if (ep->ex_fs.val[0] == fsid->val[0] && + ep->ex_fs.val[1] == fsid->val[1]) + return (ep); + ep = ep->ex_next; + } + return (ep); +} + +/* + * Add a directory path to the list. + */ +char * +add_expdir(dpp, cp, len) + struct dirlist **dpp; + char *cp; + int len; +{ + struct dirlist *dp; + + dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); + dp->dp_left = *dpp; + dp->dp_right = (struct dirlist *)NULL; + dp->dp_flag = 0; + dp->dp_hosts = (struct hostlist *)NULL; + strcpy(dp->dp_dirp, cp); + *dpp = dp; + return (dp->dp_dirp); +} + +/* + * Hang the dir list element off the dirpath binary tree as required + * and update the entry for host. + */ +void +hang_dirp(dp, grp, ep, alldirs) + struct dirlist *dp; + struct grouplist *grp; + struct exportlist *ep; + int alldirs; +{ + struct hostlist *hp; + struct dirlist *dp2; + + if (alldirs) { + if (ep->ex_defdir) + free((caddr_t)dp); + else + ep->ex_defdir = dp; + if (grp == (struct grouplist *)NULL) + ep->ex_defdir->dp_flag |= DP_DEFSET; + else while (grp) { + hp = get_ht(); + hp->ht_grp = grp; + hp->ht_next = ep->ex_defdir->dp_hosts; + ep->ex_defdir->dp_hosts = hp; + grp = grp->gr_next; + } + } else { + + /* + * Loop throught the directories adding them to the tree. + */ + while (dp) { + dp2 = dp->dp_left; + add_dlist(&ep->ex_dirl, dp, grp); + dp = dp2; + } + } +} + +/* + * Traverse the binary tree either updating a node that is already there + * for the new directory or adding the new node. + */ +void +add_dlist(dpp, newdp, grp) + struct dirlist **dpp; + struct dirlist *newdp; + struct grouplist *grp; +{ + struct dirlist *dp; + struct hostlist *hp; + int cmp; + + dp = *dpp; + if (dp) { + cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); + if (cmp > 0) { + add_dlist(&dp->dp_left, newdp, grp); + return; + } else if (cmp < 0) { + add_dlist(&dp->dp_right, newdp, grp); + return; + } else + free((caddr_t)newdp); + } else { + dp = newdp; + dp->dp_left = (struct dirlist *)NULL; + *dpp = dp; + } + if (grp) { + + /* + * Hang all of the host(s) off of the directory point. + */ + do { + hp = get_ht(); + hp->ht_grp = grp; + hp->ht_next = dp->dp_hosts; + dp->dp_hosts = hp; + grp = grp->gr_next; + } while (grp); + } else + dp->dp_flag |= DP_DEFSET; +} + +/* + * Search for a dirpath on the export point. + */ +struct dirlist * +dirp_search(dp, dirpath) + struct dirlist *dp; + char *dirpath; +{ + int cmp; + + if (dp) { + cmp = strcmp(dp->dp_dirp, dirpath); + if (cmp > 0) + return (dirp_search(dp->dp_left, dirpath)); + else if (cmp < 0) + return (dirp_search(dp->dp_right, dirpath)); + else + return (dp); + } + return (dp); +} + +/* + * Scan for a host match in a directory tree. + */ +int +chk_host(dp, saddr, defsetp) + struct dirlist *dp; + u_long saddr; + int *defsetp; +{ + struct hostlist *hp; + struct grouplist *grp; + u_long **addrp; + + if (dp) { + if (dp->dp_flag & DP_DEFSET) + *defsetp = 1; + hp = dp->dp_hosts; + while (hp) { + grp = hp->ht_grp; + switch (grp->gr_type) { + case GT_HOST: + addrp = (u_long **) + grp->gr_ptr.gt_hostent->h_addr_list; + while (*addrp) { + if (**addrp == saddr) + return (1); + addrp++; + } + break; + case GT_NET: + if ((saddr & grp->gr_ptr.gt_net.nt_mask) == + grp->gr_ptr.gt_net.nt_net) + return (1); + break; + }; + hp = hp->ht_next; + } + } + return (0); +} + +/* + * Scan tree for a host that matches the address. + */ +int +scan_tree(dp, saddr) + struct dirlist *dp; + u_long saddr; +{ + int defset; + + if (dp) { + if (scan_tree(dp->dp_left, saddr)) + return (1); + if (chk_host(dp, saddr, &defset)) + return (1); + if (scan_tree(dp->dp_right, saddr)) + return (1); + } + return (0); +} + +/* + * Traverse the dirlist tree and free it up. + */ +void +free_dir(dp) + struct dirlist *dp; +{ + + if (dp) { + free_dir(dp->dp_left); + free_dir(dp->dp_right); + free_host(dp->dp_hosts); + free((caddr_t)dp); + } +} + +/* + * Parse the option string and update fields. + * Option arguments may either be -<option>=<value> or + * -<option> <value> + */ +int +do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) + char **cpp, **endcpp; + struct exportlist *ep; + struct grouplist *grp; + int *has_hostp; + int *exflagsp; + struct ucred *cr; +{ + char *cpoptarg, *cpoptend; + char *cp, *endcp, *cpopt, savedc, savedc2; + int allflag, usedarg; + + cpopt = *cpp; + cpopt++; + cp = *endcpp; + savedc = *cp; + *cp = '\0'; + while (cpopt && *cpopt) { + allflag = 1; + usedarg = -2; + if (cpoptend = index(cpopt, ',')) { + *cpoptend++ = '\0'; + if (cpoptarg = index(cpopt, '=')) + *cpoptarg++ = '\0'; + } else { + if (cpoptarg = index(cpopt, '=')) + *cpoptarg++ = '\0'; + else { + *cp = savedc; + nextfield(&cp, &endcp); + **endcpp = '\0'; + if (endcp > cp && *cp != '-') { + cpoptarg = cp; + savedc2 = *endcp; + *endcp = '\0'; + usedarg = 0; + } + } + } + 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"))) { + usedarg++; + parsecred(cpoptarg, cr); + if (allflag == 0) { + *exflagsp |= MNT_EXPORTANON; + opt_flags |= OP_MAPALL; + } else + opt_flags |= OP_MAPROOT; + } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { + *exflagsp |= MNT_EXKERB; + opt_flags |= OP_KERB; + } else if (cpoptarg && (!strcmp(cpopt, "mask") || + !strcmp(cpopt, "m"))) { + if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { + syslog(LOG_ERR, "Bad mask: %s", cpoptarg); + return (1); + } + usedarg++; + opt_flags |= OP_MASK; + } else if (cpoptarg && (!strcmp(cpopt, "network") || + !strcmp(cpopt, "n"))) { + if (grp->gr_type != GT_NULL) { + syslog(LOG_ERR, "Network/host conflict"); + return (1); + } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { + syslog(LOG_ERR, "Bad net: %s", cpoptarg); + return (1); + } + grp->gr_type = GT_NET; + *has_hostp = 1; + usedarg++; + opt_flags |= OP_NET; + } else if (!strcmp(cpopt, "alldirs")) { + opt_flags |= OP_ALLDIRS; +#ifdef ISO + } else if (cpoptarg && !strcmp(cpopt, "iso")) { + if (get_isoaddr(cpoptarg, grp)) { + syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); + return (1); + } + *has_hostp = 1; + usedarg++; + opt_flags |= OP_ISO; +#endif /* ISO */ + } else { + syslog(LOG_ERR, "Bad opt %s", cpopt); + return (1); + } + if (usedarg >= 0) { + *endcp = savedc2; + **endcpp = savedc; + if (usedarg > 0) { + *cpp = cp; + *endcpp = endcp; + } + return (0); + } + cpopt = cpoptend; + } + **endcpp = savedc; + return (0); +} + +/* + * Translate a character string to the corresponding list of network + * addresses for a hostname. + */ +int +get_host(cp, grp) + char *cp; + struct grouplist *grp; +{ + struct hostent *hp, *nhp; + char **addrp, **naddrp; + struct hostent t_host; + int i; + u_long saddr; + char *aptr[2]; + + if (grp->gr_type != GT_NULL) + return (1); + if ((hp = gethostbyname(cp)) == NULL) { + if (isdigit(*cp)) { + saddr = inet_addr(cp); + if (saddr == -1) { + syslog(LOG_ERR, "Inet_addr failed"); + return (1); + } + if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), + AF_INET)) == NULL) { + hp = &t_host; + hp->h_name = cp; + hp->h_addrtype = AF_INET; + hp->h_length = sizeof (u_long); + hp->h_addr_list = aptr; + aptr[0] = (char *)&saddr; + aptr[1] = (char *)NULL; + } + } else { + syslog(LOG_ERR, "Gethostbyname failed"); + return (1); + } + } + grp->gr_type = GT_HOST; + nhp = grp->gr_ptr.gt_hostent = (struct hostent *) + malloc(sizeof(struct hostent)); + if (nhp == (struct hostent *)NULL) + out_of_mem(); + 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 == (char *)NULL) + out_of_mem(); + 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 == (char **)NULL) + out_of_mem(); + addrp = hp->h_addr_list; + while (*addrp) { + *naddrp = (char *) + malloc(hp->h_length); + if (*naddrp == (char *)NULL) + out_of_mem(); + bcopy(*addrp, *naddrp, + hp->h_length); + addrp++; + naddrp++; + } + *naddrp = (char *)NULL; + if (debug) + fprintf(stderr, "got host %s\n", hp->h_name); + return (0); +} + +/* + * Free up an exports list component + */ +void +free_exp(ep) + struct exportlist *ep; +{ + + if (ep->ex_defdir) { + free_host(ep->ex_defdir->dp_hosts); + free((caddr_t)ep->ex_defdir); + } + if (ep->ex_fsdir) + free(ep->ex_fsdir); + free_dir(ep->ex_dirl); + free((caddr_t)ep); +} + +/* + * Free hosts. + */ +void +free_host(hp) + struct hostlist *hp; +{ + struct hostlist *hp2; + + while (hp) { + hp2 = hp; + hp = hp->ht_next; + free((caddr_t)hp2); + } +} + +struct hostlist * +get_ht() +{ + struct hostlist *hp; + + hp = (struct hostlist *)malloc(sizeof (struct hostlist)); + if (hp == (struct hostlist *)NULL) + out_of_mem(); + hp->ht_next = (struct hostlist *)NULL; + return (hp); +} + +#ifdef ISO +/* + * Translate an iso address. + */ +get_isoaddr(cp, grp) + char *cp; + struct grouplist *grp; +{ + struct iso_addr *isop; + struct sockaddr_iso *isoaddr; + + if (grp->gr_type != GT_NULL) + return (1); + if ((isop = iso_addr(cp)) == NULL) { + syslog(LOG_ERR, + "iso_addr failed, ignored"); + return (1); + } + isoaddr = (struct sockaddr_iso *) + malloc(sizeof (struct sockaddr_iso)); + if (isoaddr == (struct sockaddr_iso *)NULL) + out_of_mem(); + 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_type = GT_ISO; + grp->gr_ptr.gt_isoaddr = isoaddr; + return (0); +} +#endif /* ISO */ + +/* + * Out of memory, fatal + */ +void +out_of_mem() +{ + + syslog(LOG_ERR, "Out of memory"); + exit(2); +} + +/* + * Do the mount syscall with the update flag to push the export info into + * the kernel. + */ +int +do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) + struct exportlist *ep; + struct grouplist *grp; + int exflags; + struct ucred *anoncrp; + char *dirp; + int dirplen; + struct statfs *fsb; +{ + char *cp = (char *)NULL; + u_long **addrp; + int done; + char savedc = '\0'; + struct sockaddr_in sin, imask; + union { + struct ufs_args ua; + struct iso_args ia; + struct mfs_args ma; + } args; + u_long net; + + args.ua.fspec = 0; + args.ua.export.ex_flags = exflags; + args.ua.export.ex_anon = *anoncrp; + bzero((char *)&sin, sizeof(sin)); + bzero((char *)&imask, sizeof(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; + else + addrp = (u_long **)NULL; + done = FALSE; + while (!done) { + switch (grp->gr_type) { + case GT_HOST: + if (addrp) { + sin.sin_addr.s_addr = **addrp; + args.ua.export.ex_addrlen = sizeof(sin); + } else + args.ua.export.ex_addrlen = 0; + args.ua.export.ex_addr = (struct sockaddr *)&sin; + args.ua.export.ex_masklen = 0; + break; + case GT_NET: + if (grp->gr_ptr.gt_net.nt_mask) + imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; + else { + net = ntohl(grp->gr_ptr.gt_net.nt_net); + if (IN_CLASSA(net)) + imask.sin_addr.s_addr = inet_addr("255.0.0.0"); + else if (IN_CLASSB(net)) + imask.sin_addr.s_addr = + inet_addr("255.255.0.0"); + else + imask.sin_addr.s_addr = + 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.ua.export.ex_addr = (struct sockaddr *)&sin; + args.ua.export.ex_addrlen = sizeof (sin); + args.ua.export.ex_mask = (struct sockaddr *)&imask; + args.ua.export.ex_masklen = sizeof (imask); + break; +#ifdef ISO + case GT_ISO: + args.ua.export.ex_addr = + (struct sockaddr *)grp->gr_ptr.gt_isoaddr; + args.ua.export.ex_addrlen = + sizeof(struct sockaddr_iso); + args.ua.export.ex_masklen = 0; + break; +#endif /* ISO */ + default: + syslog(LOG_ERR, "Bad grouptype"); + if (cp) + *cp = savedc; + return (1); + }; + + /* + * XXX: + * 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) { + if (cp) + *cp-- = savedc; + else + cp = dirp + dirplen - 1; + if (errno == EPERM) { + syslog(LOG_ERR, + "Can't change attributes for %s.\n", dirp); + return (1); + } + if (opt_flags & OP_ALLDIRS) { + syslog(LOG_ERR, "Not root dir"); + return (1); + } + /* back up over the last component */ + while (*cp == '/' && cp > dirp) + cp--; + while (*(cp - 1) != '/' && cp > dirp) + cp--; + if (cp == dirp) { + if (debug) + fprintf(stderr,"mnt unsucc\n"); + syslog(LOG_ERR, "Can't export %s", dirp); + return (1); + } + savedc = *cp; + *cp = '\0'; + } + if (addrp) { + ++addrp; + if (*addrp == (u_long *)NULL) + done = TRUE; + } else + done = TRUE; + } + if (cp) + *cp = savedc; + return (0); +} + +/* + * Translate a net address. + */ +int +get_net(cp, net, maskflg) + char *cp; + struct netmsk *net; + int maskflg; +{ + struct netent *np; + long netaddr; + struct in_addr inetaddr, inetaddr2; + char *name; + + if (np = getnetbyname(cp)) + inetaddr = inet_makeaddr(np->n_net, 0); + else if (isdigit(*cp)) { + if ((netaddr = inet_network(cp)) == -1) + return (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. + * (What a pest) + */ + if (!maskflg) { + setnetent(0); + while (np = getnetent()) { + inetaddr2 = inet_makeaddr(np->n_net, 0); + if (inetaddr2.s_addr == inetaddr.s_addr) + break; + } + endnetent(); + } + } else + return (1); + if (maskflg) + net->nt_mask = inetaddr.s_addr; + else { + if (np) + name = np->n_name; + else + name = inet_ntoa(inetaddr); + net->nt_name = (char *)malloc(strlen(name) + 1); + if (net->nt_name == (char *)NULL) + out_of_mem(); + strcpy(net->nt_name, name); + net->nt_net = inetaddr.s_addr; + } + return (0); +} + +/* + * Parse out the next white space separated field + */ +void +nextfield(cp, endcp) + char **cp; + char **endcp; +{ + char *p; + + p = *cp; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '\n' || *p == '\0') + *cp = *endcp = p; + else { + *cp = p++; + while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') + p++; + *endcp = p; + } +} + +/* + * Get an exports file line. Skip over blank lines and handle line + * continuations. + */ +int +get_line() +{ + char *p, *cp; + int len; + int totlen, cont_line; + + /* + * Loop around ignoring blank lines and getting all continuation lines. + */ + p = line; + totlen = 0; + do { + if (fgets(p, LINESIZ - totlen, exp_file) == NULL) + return (0); + len = strlen(p); + cp = p + len - 1; + cont_line = 0; + while (cp >= p && + (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { + if (*cp == '\\') + cont_line = 1; + cp--; + len--; + } + *++cp = '\0'; + if (len > 0) { + totlen += len; + if (totlen >= LINESIZ) { + syslog(LOG_ERR, "Exports line too long"); + exit(2); + } + p = cp; + } + } while (totlen == 0 || cont_line); + return (1); +} + +/* + * Parse a description of a credential. + */ +void +parsecred(namelist, cr) + char *namelist; + struct ucred *cr; +{ + char *name; + int cnt; + char *names; + struct passwd *pw; + struct group *gr; + int ngroups, groups[NGROUPS + 1]; + + /* + * Set up the unpriviledged user. + */ + cr->cr_ref = 1; + cr->cr_uid = -2; + cr->cr_groups[0] = -2; + cr->cr_ngroups = 1; + /* + * Get the user's password table entry. + */ + names = strsep(&namelist, " \t\n"); + name = strsep(&names, ":"); + if (isdigit(*name) || *name == '-') + pw = getpwuid(atoi(name)); + else + pw = getpwnam(name); + /* + * Credentials specified as those of a user. + */ + if (names == NULL) { + if (pw == NULL) { + syslog(LOG_ERR, "Unknown user: %s", name); + return; + } + cr->cr_uid = pw->pw_uid; + ngroups = NGROUPS + 1; + if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) + syslog(LOG_ERR, "Too many groups"); + /* + * 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]; + return; + } + /* + * Explicit credential specified as a colon separated list: + * uid:gid:gid:... + */ + if (pw != NULL) + cr->cr_uid = pw->pw_uid; + else if (isdigit(*name) || *name == '-') + cr->cr_uid = atoi(name); + else { + syslog(LOG_ERR, "Unknown user: %s", name); + return; + } + cr->cr_ngroups = 0; + while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { + name = strsep(&names, ":"); + if (isdigit(*name) || *name == '-') { + cr->cr_groups[cr->cr_ngroups++] = atoi(name); + } else { + if ((gr = getgrnam(name)) == NULL) { + syslog(LOG_ERR, "Unknown group: %s", name); + continue; + } + cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; + } + } + if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) + syslog(LOG_ERR, "Too many groups"); +} + +#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) +/* + * Routines that maintain the remote mounttab + */ +void +get_mountlist() +{ + struct mountlist *mlp, **mlpp; + char *eos, *dirp; + int len; + char str[STRSIZ]; + FILE *mlfile; + + if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { + syslog(LOG_ERR, "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 > RPCMNT_NAMELEN) + len = RPCMNT_NAMELEN; + 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 > RPCMNT_PATHLEN) + len = RPCMNT_PATHLEN; + bcopy(dirp, mlp->ml_dirp, len); + mlp->ml_dirp[len] = '\0'; + mlp->ml_next = (struct mountlist *)NULL; + *mlpp = mlp; + mlpp = &mlp->ml_next; + } + fclose(mlfile); +} + +void +del_mlist(hostp, dirp) + char *hostp, *dirp; +{ + struct mountlist *mlp, **mlpp; + struct mountlist *mlp2; + 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; + mlp2 = mlp; + *mlpp = mlp = mlp->ml_next; + free((caddr_t)mlp2); + } else { + mlpp = &mlp->ml_next; + mlp = mlp->ml_next; + } + } + if (fnd) { + if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { + syslog(LOG_ERR,"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) + char *hostp, *dirp; +{ + 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, 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 *)NULL; + *mlpp = mlp; + if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { + syslog(LOG_ERR, "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(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, + xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); + exit(0); +} + +int +umntall_each(resultsp, raddr) + caddr_t resultsp; + struct sockaddr_in *raddr; +{ + return (1); +} + +/* + * Free up a group list. + */ +void +free_grp(grp) + struct grouplist *grp; +{ + char **addrp; + + if (grp->gr_type == GT_HOST) { + if (grp->gr_ptr.gt_hostent->h_name) { + addrp = grp->gr_ptr.gt_hostent->h_addr_list; + while (addrp && *addrp) + free(*addrp++); + 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); + } +#ifdef ISO + else if (grp->gr_type == GT_ISO) + free((caddr_t)grp->gr_ptr.gt_isoaddr); +#endif + free((caddr_t)grp); +} + +#ifdef DEBUG +void +SYSLOG(int pri, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} +#endif /* DEBUG */ + +/* + * Check options for consistency. + */ +int +check_options(dp) + struct dirlist *dp; +{ + + if (dp == (struct dirlist *)NULL) + return (1); + 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"); + return (1); + } + if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { + syslog(LOG_ERR, "-mask requires -net"); + return (1); + } + if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { + syslog(LOG_ERR, "-net and -iso mutually exclusive"); + return (1); + } + if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { + syslog(LOG_ERR, "-alldir has multiple directories"); + return (1); + } + return (0); +} + +/* + * Check an absolute directory path for any symbolic links. Return true + * if no symbolic links are found. + */ +int +check_dirpath(dirp) + char *dirp; +{ + char *cp; + int ret = 1; + struct stat sb; + + cp = dirp + 1; + while (*cp && ret) { + if (*cp == '/') { + *cp = '\0'; + if (lstat(dirp, &sb) < 0 || + (sb.st_mode & S_IFMT) != S_IFDIR) + ret = 0; + *cp = '/'; + } + cp++; + } + if (lstat(dirp, &sb) < 0 || + (sb.st_mode & S_IFMT) != S_IFDIR) + ret = 0; + return (ret); +} diff --git a/sbin/mountd/netgroup.5 b/sbin/mountd/netgroup.5 new file mode 100644 index 0000000..9ad8c48 --- /dev/null +++ b/sbin/mountd/netgroup.5 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" 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. +.\" +.\" @(#)netgroup.5 8.2 (Berkeley) 12/11/93 +.\" +.Dd December 11, 1993 +.Dt NETGROUP 5 +.Os +.Sh NAME +.Nm netgroup +.Nd defines network groups +.Sh SYNOPSIS +.Nm netgroup +.Sh DESCRIPTION +The +.Nm netgroup +file +specifies ``netgroups'', which are sets of +.Sy (host, user, domain) +tuples that are to be given similar network access. +.Pp +Each line in the file +consists of a netgroup name followed by a list of the members of the +netgroup. +Each member can be either the name of another netgroup or a specification +of a tuple as follows: +.Bd -literal -offset indent +(host, user, domain) +.Ed +where the +.Sy host , +.Sy user , +and +.Sy domain +are character string names for the corresponding component. +Any of the comma separated fields may be empty to specify a ``wildcard'' value +or may consist of the string ``-'' to specify ``no valid value''. +The members of the list may be separated by whitespace and/or commas; +the ``\e'' character may be used at the end of a line to specify +line continuation. +The functions specified in +.Xr getnetgrent 3 +should normally be used to access the +.Nm netgroup +database. +.Pp +Lines that begin with a # are treated as comments. +.Sh FILES +.Bl -tag -width /etc/netgroup -compact +.It Pa /etc/netgroup +the netgroup database. +.El +.Sh SEE ALSO +.Xr getnetgrent 3 , +.Xr exports 5 +.Sh COMPATIBILITY +The file format is compatible with that of various vendors, however it +appears that not all vendors use an identical format. +.Sh BUGS +The interpretation of access restrictions based on the member tuples of a +netgroup is left up to the various network applications. +Also, it is not obvious how the domain specification +applies to the BSD environment. diff --git a/sbin/mountd/pathnames.h b/sbin/mountd/pathnames.h new file mode 100644 index 0000000..aa1c555 --- /dev/null +++ b/sbin/mountd/pathnames.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)pathnames.h 8.1 (Berkeley) 6/5/93 + */ +#include <paths.h> + +#define _PATH_EXPORTS "/etc/exports" +#define _PATH_RMOUNTLIST "/var/db/mountdtab" +#define _PATH_MOUNTDPID "/var/run/mountd.pid" |