diff options
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/mount_portalfs/Makefile | 15 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/activate.c | 215 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/conf.c | 329 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/mount_portalfs.8 | 136 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/mount_portalfs.c | 261 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/pathnames.h | 44 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/portal.conf | 7 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/portald.h | 82 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/pt_conf.c | 51 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/pt_exec.c | 61 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/pt_file.c | 106 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/pt_tcp.c | 158 | ||||
-rw-r--r-- | usr.sbin/mountd/Makefile | 10 | ||||
-rw-r--r-- | usr.sbin/mountd/exports.5 | 250 | ||||
-rw-r--r-- | usr.sbin/mountd/mountd.8 | 100 | ||||
-rw-r--r-- | usr.sbin/mountd/mountd.c | 2005 | ||||
-rw-r--r-- | usr.sbin/mountd/netgroup.5 | 91 | ||||
-rw-r--r-- | usr.sbin/nfsd/Makefile | 9 | ||||
-rw-r--r-- | usr.sbin/nfsd/nfsd.8 | 114 | ||||
-rw-r--r-- | usr.sbin/nfsd/nfsd.c | 589 | ||||
-rw-r--r-- | usr.sbin/nologin/Makefile | 14 | ||||
-rw-r--r-- | usr.sbin/nologin/nologin.8 | 54 | ||||
-rw-r--r-- | usr.sbin/nologin/nologin.sh | 38 |
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 |