summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorrgrimes <rgrimes@FreeBSD.org>1994-05-26 06:35:07 +0000
committerrgrimes <rgrimes@FreeBSD.org>1994-05-26 06:35:07 +0000
commitcfcc93eec947df1e540a41375912a5fa84ce75c3 (patch)
tree8575a324f257e2c8533986c80d3418e337a3ff68 /usr.sbin
parentf185bf7f09d364269a9c6dcee37a105241cf240f (diff)
downloadFreeBSD-src-cfcc93eec947df1e540a41375912a5fa84ce75c3.zip
FreeBSD-src-cfcc93eec947df1e540a41375912a5fa84ce75c3.tar.gz
BSD 4.4 Lite sbin Sources
Note: XNSrouted and routed NOT imported here, they shall be imported with usr.sbin.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/mount_portalfs/Makefile15
-rw-r--r--usr.sbin/mount_portalfs/activate.c215
-rw-r--r--usr.sbin/mount_portalfs/conf.c329
-rw-r--r--usr.sbin/mount_portalfs/mount_portalfs.8136
-rw-r--r--usr.sbin/mount_portalfs/mount_portalfs.c261
-rw-r--r--usr.sbin/mount_portalfs/pathnames.h44
-rw-r--r--usr.sbin/mount_portalfs/portal.conf7
-rw-r--r--usr.sbin/mount_portalfs/portald.h82
-rw-r--r--usr.sbin/mount_portalfs/pt_conf.c51
-rw-r--r--usr.sbin/mount_portalfs/pt_exec.c61
-rw-r--r--usr.sbin/mount_portalfs/pt_file.c106
-rw-r--r--usr.sbin/mount_portalfs/pt_tcp.c158
-rw-r--r--usr.sbin/mountd/Makefile10
-rw-r--r--usr.sbin/mountd/exports.5250
-rw-r--r--usr.sbin/mountd/mountd.8100
-rw-r--r--usr.sbin/mountd/mountd.c2005
-rw-r--r--usr.sbin/mountd/netgroup.591
-rw-r--r--usr.sbin/nfsd/Makefile9
-rw-r--r--usr.sbin/nfsd/nfsd.8114
-rw-r--r--usr.sbin/nfsd/nfsd.c589
-rw-r--r--usr.sbin/nologin/Makefile14
-rw-r--r--usr.sbin/nologin/nologin.854
-rw-r--r--usr.sbin/nologin/nologin.sh38
23 files changed, 4739 insertions, 0 deletions
diff --git a/usr.sbin/mount_portalfs/Makefile b/usr.sbin/mount_portalfs/Makefile
new file mode 100644
index 0000000..1f17d24
--- /dev/null
+++ b/usr.sbin/mount_portalfs/Makefile
@@ -0,0 +1,15 @@
+# @(#)Makefile 8.3 (Berkeley) 3/27/94
+
+PROG= mount_portal
+SRCS= mount_portal.c activate.c conf.c getmntopts.c pt_conf.c \
+ pt_exec.c pt_file.c pt_tcp.c
+MAN8= mount_portal.0
+
+MOUNT= ${.CURDIR}/../mount
+CFLAGS+= -I/sys -I${MOUNT}
+.PATH: ${MOUNT}
+
+DPADD= $(LIBCOMPAT)
+LDADD= -lcompat
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mount_portalfs/activate.c b/usr.sbin/mount_portalfs/activate.c
new file mode 100644
index 0000000..3361798
--- /dev/null
+++ b/usr.sbin/mount_portalfs/activate.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ *
+ * @(#)activate.c 8.2 (Berkeley) 3/27/94
+ *
+ * $Id: activate.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/syslog.h>
+#include <sys/uio.h>
+
+#include "portald.h"
+
+/*
+ * Scan the providers list and call the
+ * appropriate function.
+ */
+static int activate_argv(pcr, key, v, so, fdp)
+struct portal_cred *pcr;
+char *key;
+char **v;
+int so;
+int *fdp;
+{
+ provider *pr;
+
+ for (pr = providers; pr->pr_match; pr++)
+ if (strcmp(v[0], pr->pr_match) == 0)
+ return ((*pr->pr_func)(pcr, key, v, so, fdp));
+
+ return (ENOENT);
+}
+
+static int get_request(so, pcr, key, klen)
+int so;
+struct portal_cred *pcr;
+char *key;
+int klen;
+{
+ struct iovec iov[2];
+ struct msghdr msg;
+ int n;
+
+ iov[0].iov_base = (caddr_t) pcr;
+ iov[0].iov_len = sizeof(*pcr);
+ iov[1].iov_base = key;
+ iov[1].iov_len = klen;
+
+ bzero((char *) &msg, sizeof(msg));
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+
+ n = recvmsg(so, &msg, 0);
+ if (n < 0)
+ return (errno);
+
+ if (n <= sizeof(*pcr))
+ return (EINVAL);
+
+ n -= sizeof(*pcr);
+ key[n] = '\0';
+
+ return (0);
+}
+
+static void send_reply(so, fd, error)
+int so;
+int fd;
+int error;
+{
+ int n;
+ struct iovec iov;
+ struct msghdr msg;
+ struct {
+ struct cmsghdr cmsg;
+ int fd;
+ } ctl;
+
+ /*
+ * Line up error code. Don't worry about byte ordering
+ * because we must be sending to the local machine.
+ */
+ iov.iov_base = (caddr_t) &error;
+ iov.iov_len = sizeof(error);
+
+ /*
+ * Build a msghdr
+ */
+ bzero((char *) &msg, sizeof(msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ /*
+ * If there is a file descriptor to send then
+ * construct a suitable rights control message.
+ */
+ if (fd >= 0) {
+ ctl.fd = fd;
+ ctl.cmsg.cmsg_len = sizeof(ctl);
+ ctl.cmsg.cmsg_level = SOL_SOCKET;
+ ctl.cmsg.cmsg_type = SCM_RIGHTS;
+ msg.msg_control = (caddr_t) &ctl;
+ msg.msg_controllen = ctl.cmsg.cmsg_len;
+ }
+
+ /*
+ * Send to kernel...
+ */
+ if ((n = sendmsg(so, &msg, MSG_EOR)) < 0)
+ syslog(LOG_ERR, "send: %s", strerror(errno));
+#ifdef DEBUG
+ fprintf(stderr, "sent %d bytes\n", n);
+#endif
+ sleep(1); /*XXX*/
+#ifdef notdef
+ if (shutdown(so, 2) < 0)
+ syslog(LOG_ERR, "shutdown: %s", strerror(errno));
+#endif
+ /*
+ * Throw away the open file descriptor
+ */
+ (void) close(fd);
+}
+
+void activate(q, so)
+qelem *q;
+int so;
+{
+ struct portal_cred pcred;
+ char key[MAXPATHLEN+1];
+ int error;
+ char **v;
+ int fd = -1;
+
+ /*
+ * Read the key from the socket
+ */
+ error = get_request(so, &pcred, key, sizeof(key));
+ if (error) {
+ syslog(LOG_ERR, "activate: recvmsg: %s", strerror(error));
+ goto drop;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "lookup key %s\n", key);
+#endif
+
+ /*
+ * Find a match in the configuration file
+ */
+ v = conf_match(q, key);
+
+ /*
+ * If a match existed, then find an appropriate portal
+ * otherwise simply return ENOENT.
+ */
+ if (v) {
+ error = activate_argv(&pcred, key, v, so, &fd);
+ if (error)
+ fd = -1;
+ else if (fd < 0)
+ error = -1;
+ } else {
+ error = ENOENT;
+ }
+
+ if (error >= 0)
+ send_reply(so, fd, error);
+
+drop:;
+ close(so);
+}
diff --git a/usr.sbin/mount_portalfs/conf.c b/usr.sbin/mount_portalfs/conf.c
new file mode 100644
index 0000000..18833b6
--- /dev/null
+++ b/usr.sbin/mount_portalfs/conf.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ *
+ * @(#)conf.c 8.2 (Berkeley) 3/27/94
+ *
+ * $Id: conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <regexp.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+
+#include "portald.h"
+
+#define ALLOC(ty) (xmalloc(sizeof(ty)))
+
+typedef struct path path;
+struct path {
+ qelem p_q; /* 2-way linked list */
+ int p_lno; /* Line number of this record */
+ char *p_args; /* copy of arg string (malloc) */
+ char *p_key; /* Pathname to match (also p_argv[0]) */
+ regexp *p_re; /* RE to match against pathname (malloc) */
+ int p_argc; /* number of elements in arg string */
+ char **p_argv; /* argv[] pointers into arg string (malloc) */
+};
+
+static char *conf_file; /* XXX for regerror */
+static path *curp; /* XXX for regerror */
+
+/*
+ * Add an element to a 2-way list,
+ * just after (pred)
+ */
+static void ins_que(elem, pred)
+qelem *elem, *pred;
+{
+ qelem *p = pred->q_forw;
+ elem->q_back = pred;
+ elem->q_forw = p;
+ pred->q_forw = elem;
+ p->q_back = elem;
+}
+
+/*
+ * Remove an element from a 2-way list
+ */
+static void rem_que(elem)
+qelem *elem;
+{
+ qelem *p = elem->q_forw;
+ qelem *p2 = elem->q_back;
+ p2->q_forw = p;
+ p->q_back = p2;
+}
+
+/*
+ * Error checking malloc
+ */
+static void *xmalloc(siz)
+unsigned siz;
+{
+ void *p = malloc(siz);
+ if (p)
+ return (p);
+ syslog(LOG_ALERT, "malloc: failed to get %d bytes", siz);
+ exit(1);
+}
+
+/*
+ * Insert the path in the list.
+ * If there is already an element with the same key then
+ * the *second* one is ignored (return 0). If the key is
+ * not found then the path is added to the end of the list
+ * and 1 is returned.
+ */
+static int pinsert(p0, q0)
+path *p0;
+qelem *q0;
+{
+ qelem *q;
+
+ if (p0->p_argc == 0)
+ return (0);
+
+ for (q = q0->q_forw; q != q0; q = q->q_forw) {
+ path *p = (path *) q;
+ if (strcmp(p->p_key, p0->p_key) == 0)
+ return (0);
+ }
+ ins_que(&p0->p_q, q0->q_back);
+ return (1);
+
+}
+
+void regerror(s)
+const char *s;
+{
+ syslog(LOG_ERR, "%s:%s: regcomp %s: %s",
+ conf_file, curp->p_lno, curp->p_key, s);
+}
+
+static path *palloc(cline, lno)
+char *cline;
+int lno;
+{
+ int c;
+ char *s;
+ char *key;
+ path *p;
+ char **ap;
+
+ /*
+ * Implement comment chars
+ */
+ s = strchr(cline, '#');
+ if (s)
+ *s = 0;
+
+ /*
+ * Do a pass through the string to count the number
+ * of arguments
+ */
+ c = 0;
+ key = strdup(cline);
+ for (s = key; s != NULL; ) {
+ char *val;
+ while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
+ ;
+ if (val)
+ c++;
+ }
+ c++;
+ free(key);
+
+ if (c <= 1)
+ return (0);
+
+ /*
+ * Now do another pass and generate a new path structure
+ */
+ p = ALLOC(path);
+ p->p_argc = 0;
+ p->p_argv = xmalloc(c * sizeof(char *));
+ p->p_args = strdup(cline);
+ ap = p->p_argv;
+ for (s = p->p_args; s != NULL; ) {
+ char *val;
+ while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
+ ;
+ if (val) {
+ *ap++ = val;
+ p->p_argc++;
+ }
+ }
+ *ap = 0;
+
+#ifdef DEBUG
+ for (c = 0; c < p->p_argc; c++)
+ printf("%sv[%d] = %s\n", c?"\t":"", c, p->p_argv[c]);
+#endif
+
+ p->p_key = p->p_argv[0];
+ if (strpbrk(p->p_key, RE_CHARS)) {
+ curp = p; /* XXX */
+ p->p_re = regcomp(p->p_key);
+ curp = 0; /* XXX */
+ } else {
+ p->p_re = 0;
+ }
+ p->p_lno = lno;
+
+ return (p);
+}
+
+/*
+ * Free a path structure
+ */
+static void pfree(p)
+path *p;
+{
+ free(p->p_args);
+ if (p->p_re)
+ free((char *) p->p_re);
+ free((char *) p->p_argv);
+ free((char *) p);
+}
+
+/*
+ * Discard all currently held path structures on q0.
+ * and add all the ones on xq.
+ */
+static void preplace(q0, xq)
+qelem *q0;
+qelem *xq;
+{
+ /*
+ * While the list is not empty,
+ * take the first element off the list
+ * and free it.
+ */
+ while (q0->q_forw != q0) {
+ qelem *q = q0->q_forw;
+ rem_que(q);
+ pfree((path *) q);
+ }
+ while (xq->q_forw != xq) {
+ qelem *q = xq->q_forw;
+ rem_que(q);
+ ins_que(q, q0);
+ }
+}
+
+/*
+ * Read the lines from the configuration file and
+ * add them to the list of paths.
+ */
+static void readfp(q0, fp)
+qelem *q0;
+FILE *fp;
+{
+ char cline[LINE_MAX];
+ int nread = 0;
+ qelem q;
+
+ /*
+ * Make a new empty list.
+ */
+ q.q_forw = q.q_back = &q;
+
+ /*
+ * Read the lines from the configuration file.
+ */
+ while (fgets(cline, sizeof(cline), fp)) {
+ path *p = palloc(cline, nread+1);
+ if (p && !pinsert(p, &q))
+ pfree(p);
+ nread++;
+ }
+
+ /*
+ * If some records were read, then throw
+ * away the old list and replace with the
+ * new one.
+ */
+ if (nread)
+ preplace(q0, &q);
+}
+
+/*
+ * Read the configuration file (conf) and replace
+ * the existing path list with the new version.
+ * If the file is not readable, then no changes take place
+ */
+void conf_read(q, conf)
+qelem *q;
+char *conf;
+{
+ FILE *fp = fopen(conf, "r");
+ if (fp) {
+ conf_file = conf; /* XXX */
+ readfp(q, fp);
+ conf_file = 0; /* XXX */
+ (void) fclose(fp);
+ } else {
+ syslog(LOG_ERR, "open config file \"%s\": %s", conf, strerror(errno));
+ }
+}
+
+
+char **conf_match(q0, key)
+qelem *q0;
+char *key;
+{
+ qelem *q;
+
+ for (q = q0->q_forw; q != q0; q = q->q_forw) {
+ path *p = (path *) q;
+ if (p->p_re) {
+ if (regexec(p->p_re, key))
+ return (p->p_argv+1);
+ } else {
+ if (strncmp(p->p_key, key, strlen(p->p_key)) == 0)
+ return (p->p_argv+1);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/mount_portalfs/mount_portalfs.8 b/usr.sbin/mount_portalfs/mount_portalfs.8
new file mode 100644
index 0000000..0df6531
--- /dev/null
+++ b/usr.sbin/mount_portalfs/mount_portalfs.8
@@ -0,0 +1,136 @@
+.\"
+.\" Copyright (c) 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software donated to Berkeley by
+.\" Jan-Simon Pendry.
+.\"
+.\" 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.
+.\"
+.\" @(#)mount_portal.8 8.3 (Berkeley) 3/27/94
+.\"
+.\"
+.Dd March 27, 1994
+.Dt MOUNT_PORTAL 8
+.Os BSD 4.4
+.Sh NAME
+.Nm mount_portal
+.Nd mount the portal daemon
+.Sh SYNOPSIS
+.Nm mount_portal
+.Op Fl o Ar options
+.Ar /etc/portal.conf
+.Ar mount_point
+.Sh DESCRIPTION
+The
+.Nm mount_portal
+command attaches an instance of the portal daemon
+to the global filesystem namespace.
+The conventional mount point is
+.Pa /p .
+.PA /dev .
+This command is normally executed by
+.Xr mount 8
+at boot time.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl o
+Options are specified with a
+.Fl o
+flag followed by a comma separated string of options.
+See the
+.Xr mount 8
+man page for possible options and their meanings.
+.El
+.Pp
+The portal daemon provides an
+.Em open
+service.
+Objects opened under the portal mount point are
+dynamically created by the portal daemon according
+to rules specified in the named configuration file.
+Using this mechanism allows descriptors such as sockets
+to be made available in the filesystem namespace.
+.Pp
+The portal daemon works by being passed the full pathname
+of the object being opened.
+The daemon creates an appropriate descriptor according
+to the rules in the configuration file, and then passes the descriptor back
+to the calling process as the result of the open system call.
+.Sh NAMESPACE
+By convention, the portal daemon divides the namespace into sub-namespaces,
+each of which handles objects of a particular type.
+.Pp
+Currently, two sub-namespaces are implemented:
+.Pa tcp
+and
+.Pa fs .
+The
+.Pa tcp
+namespace takes a hostname and a port (slash separated) and
+creates an open TCP/IP connection.
+The
+.Pa fs
+namespace opens the named file, starting back at the root directory.
+This can be used to provide a controlled escape path from
+a chrooted environment.
+.Sh "CONFIGURATION FILE"
+The configuration file contains a list of rules.
+Each rule takes one line and consists of two or more
+whitespace separated fields.
+A hash (``#'') character causes the remainder of a line to
+be ignored. Blank lines are ignored.
+.Pp
+The first field is a pathname prefix to match
+against the requested pathname.
+If a match is found, the second field
+tells the daemon what type of object to create.
+Subsequent fields are passed to the creation function.
+.Bd -literal
+# @(#)portal.conf 5.1 (Berkeley) 7/13/92
+tcp/ tcp tcp/
+fs/ file fs/
+.Ed
+.Sh FILES
+.Bl -tag -width /p/* -compact
+.It Pa /p/*
+.El
+.Sh SEE ALSO
+.Xr mount 2 ,
+.Xr unmount 2 ,
+.Xr fstab 5 ,
+.Xr mount 8
+.Sh CAVEATS
+This filesystem may not be NFS-exported.
+.Sh HISTORY
+The
+.Nm mount_portal
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/mount_portalfs/mount_portalfs.c b/usr.sbin/mount_portalfs/mount_portalfs.c
new file mode 100644
index 0000000..ae5345d
--- /dev/null
+++ b/usr.sbin/mount_portalfs/mount_portalfs.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mount_portal.c 8.4 (Berkeley) 3/27/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/syslog.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mntopts.h"
+#include "pathnames.h"
+#include "portald.h"
+
+struct mntopt mopts[] = {
+ MOPT_STDOPTS,
+ { NULL }
+};
+
+static void usage __P((void));
+
+static sig_atomic_t readcf; /* Set when SIGHUP received */
+
+static void sigchld(sig)
+int sig;
+{
+ pid_t pid;
+
+ while ((pid = waitpid((pid_t) -1, (int *) 0, WNOHANG)) > 0)
+ ;
+ if (pid < 0)
+ syslog(LOG_WARNING, "waitpid: %s", strerror(errno));
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct portal_args args;
+ struct sockaddr_un un;
+ char *conf;
+ char *mountpt;
+ int mntflags = 0;
+ char tag[32];
+
+ qelem q;
+ int rc;
+ int so;
+ int error = 0;
+
+ /*
+ * Crack command line args
+ */
+ int ch;
+
+ while ((ch = getopt(argc, argv, "o:")) != EOF) {
+ switch (ch) {
+ case 'o':
+ getmntopts(optarg, mopts, &mntflags);
+ break;
+ default:
+ error = 1;
+ break;
+ }
+ }
+
+ if (optind != (argc - 2))
+ error = 1;
+
+ if (error)
+ usage();
+
+ /*
+ * Get config file and mount point
+ */
+ conf = argv[optind];
+ mountpt = argv[optind+1];
+
+ /*
+ * Construct the listening socket
+ */
+ un.sun_family = AF_UNIX;
+ if (sizeof(_PATH_TMPPORTAL) >= sizeof(un.sun_path)) {
+ fprintf(stderr, "mount_portal: portal socket name too long\n");
+ exit(1);
+ }
+ strcpy(un.sun_path, _PATH_TMPPORTAL);
+ mktemp(un.sun_path);
+ un.sun_len = strlen(un.sun_path);
+
+ so = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (so < 0) {
+ fprintf(stderr, "mount_portal: socket: %s\n", strerror(errno));
+ exit(1);
+ }
+ (void) unlink(un.sun_path);
+ if (bind(so, (struct sockaddr *) &un, sizeof(un)) < 0)
+ err(1, NULL);
+ (void) unlink(un.sun_path);
+
+ (void) listen(so, 5);
+
+ args.pa_socket = so;
+ sprintf(tag, "portal:%d", getpid());
+ args.pa_config = tag;
+
+ rc = mount(MOUNT_PORTAL, mountpt, mntflags, &args);
+ if (rc < 0)
+ err(1, NULL);
+
+#ifdef notdef
+ /*
+ * Everything is ready to go - now is a good time to fork
+ */
+ daemon(0, 0);
+#endif
+
+ /*
+ * Start logging (and change name)
+ */
+ openlog("portald", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ q.q_forw = q.q_back = &q;
+ readcf = 1;
+
+ signal(SIGCHLD, sigchld);
+
+ /*
+ * Just loop waiting for new connections and activating them
+ */
+ for (;;) {
+ struct sockaddr_un un2;
+ int len2 = sizeof(un2);
+ int so2;
+ pid_t pid;
+ fd_set fdset;
+ int rc;
+
+ /*
+ * Check whether we need to re-read the configuration file
+ */
+ if (readcf) {
+ readcf = 0;
+ conf_read(&q, conf);
+ continue;
+ }
+
+ /*
+ * Accept a new connection
+ * Will get EINTR if a signal has arrived, so just
+ * ignore that error code
+ */
+ FD_SET(so, &fdset);
+ rc = select(so+1, &fdset, (void *) 0, (void *) 0, (void *) 0);
+ if (rc < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %s", strerror(errno));
+ exit(1);
+ }
+ if (rc == 0)
+ break;
+ so2 = accept(so, (struct sockaddr *) &un2, &len2);
+ if (so2 < 0) {
+ /*
+ * The unmount function does a shutdown on the socket
+ * which will generated ECONNABORTED on the accept.
+ */
+ if (errno == ECONNABORTED)
+ break;
+ if (errno != EINTR) {
+ syslog(LOG_ERR, "accept: %s", strerror(errno));
+ exit(1);
+ }
+ continue;
+ }
+
+ /*
+ * Now fork a new child to deal with the connection
+ */
+ eagain:;
+ switch (pid = fork()) {
+ case -1:
+ if (errno == EAGAIN) {
+ sleep(1);
+ goto eagain;
+ }
+ syslog(LOG_ERR, "fork: %s", strerror(errno));
+ break;
+ case 0:
+ (void) close(so);
+ activate(&q, so2);
+ break;
+ default:
+ (void) close(so2);
+ break;
+ }
+ }
+ syslog(LOG_INFO, "%s unmounted", mountpt);
+ exit(0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: mount_portal [-o options] config mount-point\n");
+ exit(1);
+}
diff --git a/usr.sbin/mount_portalfs/pathnames.h b/usr.sbin/mount_portalfs/pathnames.h
new file mode 100644
index 0000000..2532114
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pathnames.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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
+ *
+ * $Id: pathnames.h,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
+ */
+
+#include <paths.h>
+
+#define _PATH_TMPPORTAL "/tmp/portalXXXXXX" /* Scratch socket name */
diff --git a/usr.sbin/mount_portalfs/portal.conf b/usr.sbin/mount_portalfs/portal.conf
new file mode 100644
index 0000000..5b5a773
--- /dev/null
+++ b/usr.sbin/mount_portalfs/portal.conf
@@ -0,0 +1,7 @@
+# @(#)portal.conf 8.1 (Berkeley) 6/5/93
+# $Id: portal.conf,v 1.1 1992/05/27 06:50:13 jsp Exp jsp $
+tcplisten/ tcplisten tcplisten/
+tcp/ tcp tcp/
+fs/ file fs/
+pipe/ pipe
+foo/ exec ./bar bar baz
diff --git a/usr.sbin/mount_portalfs/portald.h b/usr.sbin/mount_portalfs/portald.h
new file mode 100644
index 0000000..fbe111b
--- /dev/null
+++ b/usr.sbin/mount_portalfs/portald.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ *
+ * @(#)portald.h 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: portald.h,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
+ */
+
+#include <sys/cdefs.h>
+#include <miscfs/portal/portal.h>
+
+/*
+ * Meta-chars in an RE. Paths in the config file containing
+ * any of these characters will be matched using regexec, other
+ * paths will be prefix-matched.
+ */
+#define RE_CHARS ".|()[]*+?\\^$"
+
+typedef struct qelem qelem;
+
+struct qelem {
+ qelem *q_forw;
+ qelem *q_back;
+};
+
+typedef struct provider provider;
+struct provider {
+ char *pr_match;
+ int (*pr_func) __P((struct portal_cred *,
+ char *key, char **v, int so, int *fdp));
+};
+extern provider providers[];
+
+/*
+ * Portal providers
+ */
+extern int portal_exec __P((struct portal_cred *,
+ char *key, char **v, int so, int *fdp));
+extern int portal_file __P((struct portal_cred *,
+ char *key, char **v, int so, int *fdp));
+extern int portal_tcp __P((struct portal_cred *,
+ char *key, char **v, int so, int *fdp));
+
+/*
+ * Global functions
+ */
+extern void activate __P((qelem *q, int so));
+extern char **conf_match __P((qelem *q, char *key));
+extern void conf_read __P((qelem *q, char *conf));
diff --git a/usr.sbin/mount_portalfs/pt_conf.c b/usr.sbin/mount_portalfs/pt_conf.c
new file mode 100644
index 0000000..d1eba94
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pt_conf.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ *
+ * @(#)pt_conf.c 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: pt_conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include "portald.h"
+
+provider providers[] = {
+ { "exec", portal_exec },
+ { "file", portal_file },
+ { "tcp", portal_tcp },
+ { 0, 0 }
+};
diff --git a/usr.sbin/mount_portalfs/pt_exec.c b/usr.sbin/mount_portalfs/pt_exec.c
new file mode 100644
index 0000000..06e3382
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pt_exec.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ *
+ * @(#)pt_exec.c 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: pt_exec.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+
+#include "portald.h"
+
+int portal_exec(pcr, key, v, so, fdp)
+struct portal_cred *pcr;
+char *key;
+char **v;
+int so;
+int *fdp;
+{
+ return (ENOEXEC);
+}
+
diff --git a/usr.sbin/mount_portalfs/pt_file.c b/usr.sbin/mount_portalfs/pt_file.c
new file mode 100644
index 0000000..ace35c0
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pt_file.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ *
+ * @(#)pt_file.c 8.2 (Berkeley) 3/27/94
+ *
+ * $Id: pt_file.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+
+#include "portald.h"
+
+int portal_file(pcr, key, v, so, fdp)
+struct portal_cred *pcr;
+char *key;
+char **v;
+int so;
+int *fdp;
+{
+ int fd;
+ char pbuf[MAXPATHLEN];
+ int error;
+ int gidset[NGROUPS];
+ int i;
+
+ pbuf[0] = '/';
+ strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0));
+
+#ifdef DEBUG
+ printf("path = %s, uid = %d, gid = %d\n", pbuf, pcr->pcr_uid, pcr->pcr_groups[0]);
+#endif
+
+ for (i = 0; i < pcr->pcr_ngroups; i++)
+ gidset[i] = pcr->pcr_groups[i];
+
+ if (setgroups(pcr->pcr_ngroups, gidset) < 0)
+ return (errno);
+
+ if (seteuid(pcr->pcr_uid) < 0)
+ return (errno);
+
+ fd = open(pbuf, O_RDWR|O_CREAT, 0666);
+ if (fd < 0)
+ error = errno;
+ else
+ error = 0;
+
+ if (seteuid((uid_t) 0) < 0) { /* XXX - should reset gidset too */
+ error = errno;
+ syslog(LOG_ERR, "setcred: %s", strerror(error));
+ if (fd >= 0) {
+ (void) close(fd);
+ fd = -1;
+ }
+ }
+
+ if (error == 0)
+ *fdp = fd;
+
+#ifdef DEBUG
+ fprintf(stderr, "pt_file returns *fdp = %d, error = %d\n", *fdp, error);
+#endif
+
+ return (error);
+}
diff --git a/usr.sbin/mount_portalfs/pt_tcp.c b/usr.sbin/mount_portalfs/pt_tcp.c
new file mode 100644
index 0000000..18a53ce
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pt_tcp.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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.
+ *
+ * @(#)pt_tcp.c 8.3 (Berkeley) 3/27/94
+ *
+ * $Id: pt_tcp.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "portald.h"
+
+/*
+ * Key will be tcp/host/port[/"priv"]
+ * Create a TCP socket connected to the
+ * requested host and port.
+ * Some trailing suffix values have special meanings.
+ * An unrecognised suffix is an error.
+ */
+int portal_tcp(pcr, key, v, kso, fdp)
+struct portal_cred *pcr;
+char *key;
+char **v;
+int kso;
+int *fdp;
+{
+ char host[MAXHOSTNAMELEN];
+ char port[MAXHOSTNAMELEN];
+ char *p = key + (v[1] ? strlen(v[1]) : 0);
+ char *q;
+ struct hostent *hp;
+ struct servent *sp;
+ struct in_addr **ipp;
+ struct in_addr *ip[2];
+ struct in_addr ina;
+ int s_port;
+ int priv = 0;
+ struct sockaddr_in sain;
+
+ q = strchr(p, '/');
+ if (q == 0 || q - p >= sizeof(host))
+ return (EINVAL);
+ *q = '\0';
+ strcpy(host, p);
+ p = q + 1;
+
+ q = strchr(p, '/');
+ if (q)
+ *q = '\0';
+ if (strlen(p) >= sizeof(port))
+ return (EINVAL);
+ strcpy(port, p);
+ if (q) {
+ p = q + 1;
+ if (strcmp(p, "priv") == 0) {
+ if (pcr->pcr_uid == 0)
+ priv = 1;
+ else
+ return (EPERM);
+ } else {
+ return (EINVAL);
+ }
+ }
+
+ hp = gethostbyname(host);
+ if (hp != 0) {
+ ipp = (struct in_addr **) hp->h_addr_list;
+ } else {
+ ina.s_addr = inet_addr(host);
+ if (ina.s_addr == INADDR_NONE)
+ return (EINVAL);
+ ip[0] = &ina;
+ ip[1] = 0;
+ ipp = ip;
+ }
+
+ sp = getservbyname(port, "tcp");
+ if (sp != 0)
+ s_port = sp->s_port;
+ else {
+ s_port = atoi(port);
+ if (s_port == 0)
+ return (EINVAL);
+ }
+
+ bzero(&sain, sizeof(sain));
+ sain.sin_len = sizeof(sain);
+ sain.sin_family = AF_INET;
+ sain.sin_port = s_port;
+
+ while (ipp[0]) {
+ int so;
+
+ if (priv)
+ so = rresvport((int *) 0);
+ else
+ so = socket(AF_INET, SOCK_STREAM, 0);
+ if (so < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ return (errno);
+ }
+
+ sain.sin_addr = *ipp[0];
+ if (connect(so, (struct sockaddr *) &sain, sizeof(sain)) == 0) {
+ *fdp = so;
+ return (0);
+ }
+ (void) close(so);
+
+ ipp++;
+ }
+
+ return (errno);
+}
diff --git a/usr.sbin/mountd/Makefile b/usr.sbin/mountd/Makefile
new file mode 100644
index 0000000..36e2a05
--- /dev/null
+++ b/usr.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/usr.sbin/mountd/exports.5 b/usr.sbin/mountd/exports.5
new file mode 100644
index 0000000..d32527f
--- /dev/null
+++ b/usr.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/usr.sbin/mountd/mountd.8 b/usr.sbin/mountd/mountd.8
new file mode 100644
index 0000000..47a6cfc
--- /dev/null
+++ b/usr.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/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
new file mode 100644
index 0000000..d7c31df
--- /dev/null
+++ b/usr.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/usr.sbin/mountd/netgroup.5 b/usr.sbin/mountd/netgroup.5
new file mode 100644
index 0000000..9ad8c48
--- /dev/null
+++ b/usr.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/usr.sbin/nfsd/Makefile b/usr.sbin/nfsd/Makefile
new file mode 100644
index 0000000..35d0d0e
--- /dev/null
+++ b/usr.sbin/nfsd/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+PROG= nfsd
+CFLAGS+=-DNFS
+MAN8= nfsd.0
+DPADD= ${LIBRPC}
+LDADD= -lrpc
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/nfsd/nfsd.8 b/usr.sbin/nfsd/nfsd.8
new file mode 100644
index 0000000..4ee6c4b
--- /dev/null
+++ b/usr.sbin/nfsd/nfsd.8
@@ -0,0 +1,114 @@
+.\" 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.
+.\"
+.\" @(#)nfsd.8 8.3 (Berkeley) 2/22/94
+.\"
+.Dd February 22, 1994
+.Dt NFSD 8
+.Os
+.Sh NAME
+.Nm nfsd
+.Nd remote
+.Tn NFS
+server
+.Sh SYNOPSIS
+.Nm nfsd
+.Op Fl rut
+.Op Fl n Ar num_servers
+.Sh DESCRIPTION
+.Nm Nfsd
+runs on a server machine to service
+.Tn NFS
+requests from client machines.
+At least one
+.Nm nfsd
+must be running for a machine to operate as a server.
+.Pp
+Unless otherwise specified, four servers for
+.Tn UDP
+transport are started.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl r
+Register the
+.Tn NFS
+service with
+.Xr portmap 8
+without creating any servers.
+This option can be used along with the
+.Fl u
+or
+.Fl t
+options to re-register NFS if the portmap server is restarted.
+.It Fl n
+Specifies how many servers to create.
+.It Fl t
+Serve
+.Tn TCP NFS
+clients.
+.It Fl u
+Serve
+.Tn UDP NFS
+clients.
+.El
+.Pp
+For example,
+.Dq Li "nfsd -u -t 6"
+serves
+.Tn UDP
+and
+.Tn TCP
+transports using six daemons.
+.Pp
+A server should run enough daemons to handle
+the maximum level of concurrency from its clients,
+typically four to six.
+.Pp
+.Nm Nfsd
+listens for service requests at the port indicated in the
+.Tn NFS
+server specification; see
+.%T "Network File System Protocol Specification" ,
+RFC1094.
+.Pp
+The
+.Nm nfsd
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr nfsstat 1 ,
+.Xr nfssvc 2 ,
+.Xr mountd 8 ,
+.Xr portmap 8
+.Sh HISTORY
+The
+.Nm nfsd
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/nfsd/nfsd.c b/usr.sbin/nfsd/nfsd.c
new file mode 100644
index 0000000..63f4f00
--- /dev/null
+++ b/usr.sbin/nfsd/nfsd.c
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif not lint
+
+#ifndef lint
+static char sccsid[] = "@(#)nfsd.c 8.7 (Berkeley) 2/22/94";
+#endif not lint
+
+#include <sys/param.h>
+#include <sys/syslog.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/uio.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/socketvar.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 <nfs/nfs.h>
+
+#ifdef KERBEROS
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+/* Global defs */
+#ifdef DEBUG
+#define syslog(e, s) fprintf(stderr,(s))
+int debug = 1;
+#else
+int debug = 0;
+#endif
+
+struct nfsd_srvargs nsd;
+char **Argv = NULL; /* pointer to argument vector */
+char *LastArg = NULL; /* end of argv */
+
+#ifdef KERBEROS
+char lnam[ANAME_SZ];
+KTEXT_ST kt;
+AUTH_DAT auth;
+char inst[INST_SZ];
+#endif
+
+void nonfs __P((int));
+void reapchild __P((int));
+void setproctitle __P((char *));
+void usage __P((void));
+
+/*
+ * Nfs server daemon mostly just a user context for nfssvc()
+ *
+ * 1 - do file descriptor and signal cleanup
+ * 2 - fork the nfsd(s)
+ * 3 - create server socket(s)
+ * 4 - register socket with portmap
+ *
+ * For connectionless protocols, just pass the socket into the kernel via.
+ * nfssvc().
+ * For connection based sockets, loop doing accepts. When you get a new
+ * socket from accept, pass the msgsock into the kernel via. nfssvc().
+ * The arguments are:
+ * -c - support iso cltp clients
+ * -r - reregister with portmapper
+ * -t - support tcp nfs clients
+ * -u - support udp nfs clients
+ * followed by "n" which is the number of nfsds' to fork off
+ */
+int
+main(argc, argv, envp)
+ int argc;
+ char *argv[], *envp[];
+{
+ extern int optind;
+ struct group *grp;
+ struct nfsd_args nfsdargs;
+ struct passwd *pwd;
+ struct ucred *cr;
+ struct sockaddr_in inetaddr, inetpeer;
+#ifdef ISO
+ struct sockaddr_iso isoaddr, isopeer;
+#endif
+ fd_set ready, sockbits;
+ int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
+ int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
+ int tp4cnt, tp4flag, tp4sock, tpipcnt, tpipflag, tpipsock, udpflag;
+ char *cp, **cpp;
+
+ /* Save start and extent of argv for setproctitle. */
+ Argv = argv;
+ if (envp == 0 || *envp == 0)
+ envp = argv;
+ while (*envp)
+ envp++;
+ LastArg = envp[-1] + strlen(envp[-1]);
+
+#define MAXNFSDCNT 20
+#define DEFNFSDCNT 4
+ nfsdcnt = DEFNFSDCNT;
+ cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
+ tpipflag = udpflag = 0;
+#ifdef ISO
+#define GETOPT "cn:rtu"
+#define USAGE "[-crtu] [-n num_servers]"
+#else
+#define GETOPT "n:rtu"
+#define USAGE "[-rtu] [-n num_servers]"
+#endif
+ while ((ch = getopt(argc, argv, GETOPT)) != EOF)
+ switch (ch) {
+ case 'n':
+ nfsdcnt = atoi(optarg);
+ if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
+ warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
+ nfsdcnt = DEFNFSDCNT;
+ }
+ break;
+ case 'r':
+ reregister = 1;
+ break;
+ case 't':
+ tcpflag = 1;
+ break;
+ case 'u':
+ udpflag = 1;
+ break;
+#ifdef ISO
+ case 'c':
+ cltpflag = 1;
+ break;
+#ifdef notyet
+ case 'i':
+ tp4cnt = 1;
+ break;
+ case 'p':
+ tpipcnt = 1;
+ break;
+#endif /* notyet */
+#endif /* ISO */
+ default:
+ case '?':
+ usage();
+ };
+ argv += optind;
+ argc -= optind;
+
+ /*
+ * XXX
+ * Backward compatibility, trailing number is the count of daemons.
+ */
+ if (argc > 1)
+ usage();
+ if (argc == 1) {
+ nfsdcnt = atoi(argv[0]);
+ if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
+ warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
+ nfsdcnt = DEFNFSDCNT;
+ }
+ }
+
+ if (debug == 0) {
+ daemon(0, 0);
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGSYS, nonfs);
+ (void)signal(SIGTERM, SIG_IGN);
+ }
+ (void)signal(SIGCHLD, reapchild);
+
+ if (reregister) {
+ if (udpflag &&
+ !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT))
+ err(1, "can't register with portmap for UDP.");
+ if (tcpflag &&
+ !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT))
+ err(1, "can't register with portmap for TCP.");
+ exit(0);
+ }
+ openlog("nfsd:", LOG_PID, LOG_DAEMON);
+
+ for (i = 0; i < nfsdcnt; i++) {
+ switch (fork()) {
+ case -1:
+ syslog(LOG_ERR, "fork: %m");
+ exit (1);
+ case 0:
+ break;
+ default:
+ continue;
+ }
+
+ setproctitle("nfsd-srv");
+ nfssvc_flag = NFSSVC_NFSD;
+ nsd.nsd_nfsd = NULL;
+#ifdef KERBEROS
+ nsd.nsd_authstr = (char *)kt.dat;
+#endif
+ while (nfssvc(nfssvc_flag, &nsd) < 0) {
+ if (errno != ENEEDAUTH) {
+ syslog(LOG_ERR, "nfssvc: %m");
+ exit(1);
+ }
+ nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
+#ifdef KERBEROS
+ kt.length = nsd.nsd_authlen;
+ kt.mbz = 0;
+ (void)strcpy(inst, "*");
+ if (krb_rd_req(&kt, "rcmd",
+ inst, nsd.nsd_haddr, &auth, "") == RD_AP_OK &&
+ krb_kntoln(&auth, lnam) == KSUCCESS &&
+ (pwd = getpwnam(lnam)) != NULL) {
+ cr = &nsd.nsd_cr;
+ cr->cr_uid = pwd->pw_uid;
+ cr->cr_groups[0] = pwd->pw_gid;
+ cr->cr_ngroups = 1;
+ setgrent();
+ while ((grp = getgrent()) != NULL) {
+ if (grp->gr_gid == cr->cr_groups[0])
+ continue;
+ for (cpp = grp->gr_mem;
+ *cpp != NULL; ++cpp)
+ if (!strcmp(*cpp, lnam))
+ break;
+ if (*cpp == NULL)
+ continue;
+ cr->cr_groups[cr->cr_ngroups++]
+ = grp->gr_gid;
+ if (cr->cr_ngroups == NGROUPS)
+ break;
+ }
+ endgrent();
+ nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
+ }
+#endif /* KERBEROS */
+ }
+ exit(0);
+ }
+
+ /* If we are serving udp, set up the socket. */
+ if (udpflag) {
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "can't create udp socket");
+ exit(1);
+ }
+ inetaddr.sin_family = AF_INET;
+ inetaddr.sin_addr.s_addr = INADDR_ANY;
+ inetaddr.sin_port = htons(NFS_PORT);
+ inetaddr.sin_len = sizeof(inetaddr);
+ if (bind(sock,
+ (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind udp addr");
+ exit(1);
+ }
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register with udp portmap");
+ exit(1);
+ }
+ nfsdargs.sock = sock;
+ nfsdargs.name = NULL;
+ nfsdargs.namelen = 0;
+ if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
+ syslog(LOG_ERR, "can't Add UDP socket");
+ exit(1);
+ }
+ (void)close(sock);
+ }
+
+#ifdef ISO
+ /* If we are serving cltp, set up the socket. */
+ if (cltpflag) {
+ if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "can't create cltp socket");
+ exit(1);
+ }
+ memset(&isoaddr, 0, sizeof(isoaddr));
+ isoaddr.siso_family = AF_ISO;
+ isoaddr.siso_tlen = 2;
+ cp = TSEL(&isoaddr);
+ *cp++ = (NFS_PORT >> 8);
+ *cp = (NFS_PORT & 0xff);
+ isoaddr.siso_len = sizeof(isoaddr);
+ if (bind(sock,
+ (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind cltp addr");
+ exit(1);
+ }
+#ifdef notyet
+ /*
+ * XXX
+ * Someday this should probably use "rpcbind", the son of
+ * portmap.
+ */
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register with udp portmap");
+ exit(1);
+ }
+#endif /* notyet */
+ nfsdargs.sock = sock;
+ nfsdargs.name = NULL;
+ nfsdargs.namelen = 0;
+ if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
+ syslog(LOG_ERR, "can't add UDP socket");
+ exit(1);
+ }
+ close(sock);
+ }
+#endif /* ISO */
+
+ /* Now set up the master server socket waiting for tcp connections. */
+ on = 1;
+ FD_ZERO(&sockbits);
+ connect_type_cnt = 0;
+ if (tcpflag) {
+ if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "can't create tcp socket");
+ exit(1);
+ }
+ if (setsockopt(tcpsock,
+ SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
+ inetaddr.sin_family = AF_INET;
+ inetaddr.sin_addr.s_addr = INADDR_ANY;
+ inetaddr.sin_port = htons(NFS_PORT);
+ inetaddr.sin_len = sizeof(inetaddr);
+ if (bind(tcpsock,
+ (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind tcp addr");
+ exit(1);
+ }
+ if (listen(tcpsock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register tcp with portmap");
+ exit(1);
+ }
+ FD_SET(tcpsock, &sockbits);
+ maxsock = tcpsock;
+ connect_type_cnt++;
+ }
+
+#ifdef notyet
+ /* Now set up the master server socket waiting for tp4 connections. */
+ if (tp4flag) {
+ if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
+ syslog(LOG_ERR, "can't create tp4 socket");
+ exit(1);
+ }
+ if (setsockopt(tp4sock,
+ SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
+ memset(&isoaddr, 0, sizeof(isoaddr));
+ isoaddr.siso_family = AF_ISO;
+ isoaddr.siso_tlen = 2;
+ cp = TSEL(&isoaddr);
+ *cp++ = (NFS_PORT >> 8);
+ *cp = (NFS_PORT & 0xff);
+ isoaddr.siso_len = sizeof(isoaddr);
+ if (bind(tp4sock,
+ (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind tp4 addr");
+ exit(1);
+ }
+ if (listen(tp4sock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ /*
+ * XXX
+ * Someday this should probably use "rpcbind", the son of
+ * portmap.
+ */
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register tcp with portmap");
+ exit(1);
+ }
+ FD_SET(tp4sock, &sockbits);
+ maxsock = tp4sock;
+ connect_type_cnt++;
+ }
+
+ /* Now set up the master server socket waiting for tpip connections. */
+ if (tpipflag) {
+ if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
+ syslog(LOG_ERR, "can't create tpip socket");
+ exit(1);
+ }
+ if (setsockopt(tpipsock,
+ SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
+ inetaddr.sin_family = AF_INET;
+ inetaddr.sin_addr.s_addr = INADDR_ANY;
+ inetaddr.sin_port = htons(NFS_PORT);
+ inetaddr.sin_len = sizeof(inetaddr);
+ if (bind(tpipsock,
+ (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind tcp addr");
+ exit(1);
+ }
+ if (listen(tpipsock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ /*
+ * XXX
+ * Someday this should probably use "rpcbind", the son of
+ * portmap.
+ */
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register tcp with portmap");
+ exit(1);
+ }
+ FD_SET(tpipsock, &sockbits);
+ maxsock = tpipsock;
+ connect_type_cnt++;
+ }
+#endif /* notyet */
+
+ if (connect_type_cnt == 0)
+ exit(0);
+
+ setproctitle("nfsd-master");
+
+ /*
+ * Loop forever accepting connections and passing the sockets
+ * into the kernel for the mounts.
+ */
+ for (;;) {
+ ready = sockbits;
+ if (connect_type_cnt > 1) {
+ if (select(maxsock + 1,
+ &ready, NULL, NULL, NULL) < 1) {
+ syslog(LOG_ERR, "select failed: %m");
+ exit(1);
+ }
+ }
+ if (tcpflag && FD_ISSET(tcpsock, &ready)) {
+ len = sizeof(inetpeer);
+ if ((msgsock = accept(tcpsock,
+ (struct sockaddr *)&inetpeer, &len)) < 0) {
+ syslog(LOG_ERR, "accept failed: %m");
+ exit(1);
+ }
+ memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inetpeer;
+ nfsdargs.namelen = sizeof(inetpeer);
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ }
+#ifdef notyet
+ if (tp4flag && FD_ISSET(tp4sock, &ready)) {
+ len = sizeof(isopeer);
+ if ((msgsock = accept(tp4sock,
+ (struct sockaddr *)&isopeer, &len)) < 0) {
+ syslog(LOG_ERR, "accept failed: %m");
+ exit(1);
+ }
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&isopeer;
+ nfsdargs.namelen = len;
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ }
+ if (tpipflag && FD_ISSET(tpipsock, &ready)) {
+ len = sizeof(inetpeer);
+ if ((msgsock = accept(tpipsock,
+ (struct sockaddr *)&inetpeer, &len)) < 0) {
+ syslog(LOG_ERR, "Accept failed: %m");
+ exit(1);
+ }
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inetpeer;
+ nfsdargs.namelen = len;
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ }
+#endif /* notyet */
+ }
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "nfsd %s\n", USAGE);
+ exit(1);
+}
+
+void
+nonfs(signo)
+ int signo;
+{
+ syslog(LOG_ERR, "missing system call: NFS not available.");
+}
+
+void
+reapchild(signo)
+ int signo;
+{
+
+ while (wait3(NULL, WNOHANG, NULL));
+}
+
+void
+setproctitle(a)
+ char *a;
+{
+ register char *cp;
+ char buf[80];
+
+ cp = Argv[0];
+ (void)snprintf(buf, sizeof(buf), "%s", a);
+ (void)strncpy(cp, buf, LastArg - cp);
+ cp += strlen(cp);
+ while (cp < LastArg)
+ *cp++ = ' ';
+}
diff --git a/usr.sbin/nologin/Makefile b/usr.sbin/nologin/Makefile
new file mode 100644
index 0000000..84e9f0c
--- /dev/null
+++ b/usr.sbin/nologin/Makefile
@@ -0,0 +1,14 @@
+# @(#)Makefile 8.2 (Berkeley) 4/22/94
+
+MAN8= nologin.0
+
+nologin clean depend lint tags:
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/nologin.sh ${DESTDIR}/sbin/nologin
+
+cleandir:
+ rm -f nologin.0
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/nologin/nologin.8 b/usr.sbin/nologin/nologin.8
new file mode 100644
index 0000000..32a7e73
--- /dev/null
+++ b/usr.sbin/nologin/nologin.8
@@ -0,0 +1,54 @@
+.\" Copyright (c) 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.
+.\"
+.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93
+.\"
+.Dd June 19, 1993
+.Dt NOLOGIN 8
+.Os BSD 4.4
+.Sh NAME
+.Nm nologin
+.Nd politely refuse a login
+.Sh SYNOPSIS
+.Nm nologin
+.Sh DESCRIPTION
+.Nm Nologin
+displays a message that an account is not available and
+exits non-zero.
+It is intended as a replacement shell field for accounts that
+have been disabled.
+.Sh SEE ALSO
+.Xr login 1
+.Sh HISTORY
+The
+.Nm nologin
+command appeared in
+.Bx 4.4 .
diff --git a/usr.sbin/nologin/nologin.sh b/usr.sbin/nologin/nologin.sh
new file mode 100644
index 0000000..8ad87fb
--- /dev/null
+++ b/usr.sbin/nologin/nologin.sh
@@ -0,0 +1,38 @@
+#!/bin/sh -
+#
+# 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.
+#
+# @(#)nologin.sh 8.1 (Berkeley) 6/5/93
+#
+
+echo 'This account is currently not available.'
+exit 1
OpenPOWER on IntegriCloud