diff options
author | dds <dds@FreeBSD.org> | 2005-03-10 22:10:16 +0000 |
---|---|---|
committer | dds <dds@FreeBSD.org> | 2005-03-10 22:10:16 +0000 |
commit | 308ddcd19d4af9a37e2b55a0c2e5c21f02d42759 (patch) | |
tree | 078062a7c756e2e4e25f1aa752e7490e807e9957 /usr.sbin | |
parent | d7dbc74b2cdb6924d8cd8bc6885d65fe5f5c8e12 (diff) | |
download | FreeBSD-src-308ddcd19d4af9a37e2b55a0c2e5c21f02d42759.zip FreeBSD-src-308ddcd19d4af9a37e2b55a0c2e5c21f02d42759.tar.gz |
Add a new pipe sub-namespace.
This allows us to:
- perform scatter gather operations without using temporary files,
- create non-linear pipelines, and
- implement file views using symbolic links.
File view idea by: Vassilios Karakoidas
Portalfs pointer by: John Ioannidis
MFC after: 1 month
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/mount_portalfs/Makefile | 2 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/portal.conf | 2 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/portald.h | 2 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/pt_conf.c | 1 | ||||
-rw-r--r-- | usr.sbin/mount_portalfs/pt_pipe.c | 247 |
5 files changed, 252 insertions, 2 deletions
diff --git a/usr.sbin/mount_portalfs/Makefile b/usr.sbin/mount_portalfs/Makefile index 56667f1..5ee42da 100644 --- a/usr.sbin/mount_portalfs/Makefile +++ b/usr.sbin/mount_portalfs/Makefile @@ -3,7 +3,7 @@ PROG= mount_portalfs SRCS= mount_portalfs.c activate.c conf.c getmntopts.c pt_conf.c \ - pt_exec.c pt_file.c pt_tcp.c pt_tcplisten.c + pt_exec.c pt_file.c pt_pipe.c pt_tcp.c pt_tcplisten.c MAN= mount_portalfs.8 MOUNT= ${.CURDIR}/../../sbin/mount diff --git a/usr.sbin/mount_portalfs/portal.conf b/usr.sbin/mount_portalfs/portal.conf index 53a07a9..398cfb2 100644 --- a/usr.sbin/mount_portalfs/portal.conf +++ b/usr.sbin/mount_portalfs/portal.conf @@ -3,5 +3,5 @@ tcplisten/ tcplisten tcplisten/ tcp/ tcp tcp/ fs/ file fs/ -pipe/ pipe +pipe/ pipe pipe/ foo/ exec ./bar bar baz diff --git a/usr.sbin/mount_portalfs/portald.h b/usr.sbin/mount_portalfs/portald.h index ceb1a465..bf8b50b 100644 --- a/usr.sbin/mount_portalfs/portald.h +++ b/usr.sbin/mount_portalfs/portald.h @@ -67,6 +67,8 @@ extern int portal_exec(struct portal_cred *, char *key, char **v, int so, int *fdp); extern int portal_file(struct portal_cred *, char *key, char **v, int so, int *fdp); +extern int portal_pipe(struct portal_cred *, + char *key, char **v, int so, int *fdp); extern int portal_tcp(struct portal_cred *, char *key, char **v, int so, int *fdp); extern int portal_tcplisten(struct portal_cred *, diff --git a/usr.sbin/mount_portalfs/pt_conf.c b/usr.sbin/mount_portalfs/pt_conf.c index a89232d..7f1e817 100644 --- a/usr.sbin/mount_portalfs/pt_conf.c +++ b/usr.sbin/mount_portalfs/pt_conf.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); provider providers[] = { { "exec", portal_exec }, { "file", portal_file }, + { "pipe", portal_pipe }, { "tcp", portal_tcp }, { "tcplisten", portal_tcplisten }, { 0, 0 } diff --git a/usr.sbin/mount_portalfs/pt_pipe.c b/usr.sbin/mount_portalfs/pt_pipe.c new file mode 100644 index 0000000..6a2a24e --- /dev/null +++ b/usr.sbin/mount_portalfs/pt_pipe.c @@ -0,0 +1,247 @@ +/*- + * Copyright (C) 1005 Diomidis Spinellis. 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/syslog.h> + +#include "portald.h" + +/* Usage conventions for the pipe's endpoints. */ +#define READ_END 0 +#define WRITE_END 1 + +static int errlog(void); +static int parse_argv(char *args, char **argv); + +int portal_pipe(pcr, key, v, so, fdp) +struct portal_cred *pcr; +char *key; +char **v; +int so; +int *fdp; +{ + int fd[2]; /* Pipe endpoints. */ + int caller_end; /* The pipe end we will use. */ + int process_end; /* The pipe end the spawned process will use. */ + int redirect_fd; /* The fd to redirect on the spawned process. */ + char pbuf[MAXPATHLEN]; + int error = 0; + int i; + char **argv; + int argc; + /* Variables used to save the the caller's credentials. */ + uid_t old_uid; + int ngroups; + gid_t old_groups[NGROUPS_MAX]; + + /* Validate open mode, and assign roles. */ + if ((pcr->pcr_flag & FWRITE) && (pcr->pcr_flag & FREAD)) + /* Don't allow both on a single fd. */ + return (EINVAL); + else if (pcr->pcr_flag & FREAD) { + /* + * The caller reads from the pipe, + * the spawned process writes to it. + */ + caller_end = READ_END; + process_end = WRITE_END; + redirect_fd = STDOUT_FILENO; + } else if (pcr->pcr_flag & FWRITE) { + /* + * The caller writes to the pipe, + * the spawned process reads from it. + */ + caller_end = WRITE_END; + process_end = READ_END; + redirect_fd = STDIN_FILENO; + } else + return (EINVAL); + + /* Get and check command line. */ + pbuf[0] = '/'; + strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0)); + argc = parse_argv(pbuf, NULL); + if (argc == 0) + return (ENOENT); + + /* Swap priviledges. */ + old_uid = geteuid(); + if ((ngroups = getgroups(NGROUPS_MAX, old_groups)) < 0) + return (errno); + if (setgroups(pcr->pcr_ngroups, pcr->pcr_groups) < 0) + return (errno); + if (seteuid(pcr->pcr_uid) < 0) + return (errno); + + /* Redirect and spawn the specified process. */ + fd[READ_END] = fd[WRITE_END] = -1; + if (pipe(fd) < 0) { + error = errno; + goto done; + } + switch (fork()) { + case -1: /* Error */ + error = errno; + break; + default: /* Parent */ + (void)close(fd[process_end]); + break; + case 0: /* Child */ + argv = (char **)malloc((argc + 1) * sizeof(char *)); + if (argv == 0) { + syslog(LOG_ALERT, + "malloc: failed to get space for %d pointers", + argc + 1); + exit(EXIT_FAILURE); + } + parse_argv(pbuf, argv); + + if (dup2(fd[process_end], redirect_fd) < 0) { + syslog(LOG_ERR, "dup2: %m"); + exit(EXIT_FAILURE); + } + (void)close(fd[caller_end]); + (void)close(fd[process_end]); + if (errlog() < 0) { + syslog(LOG_ERR, "errlog: %m"); + exit(EXIT_FAILURE); + } + if (execv(argv[0], argv) < 0) { + syslog(LOG_ERR, "execv(%s): %m", argv[0]); + exit(EXIT_FAILURE); + } + /* NOTREACHED */ + } + +done: + /* Re-establish our priviledges. */ + if (seteuid(old_uid) < 0) { + error = errno; + syslog(LOG_ERR, "seteuid: %m"); + } + if (setgroups(ngroups, old_groups) < 0) { + error = errno; + syslog(LOG_ERR, "setgroups: %m"); + } + + /* Set return fd value. */ + if (error == 0) + *fdp = fd[caller_end]; + else { + for (i = 0; i < 2; i++) + if (fd[i] >= 0) + (void)close(fd[i]); + *fdp = -1; + } + + return (error); +} + +/* + * Redirect stderr to the system log. + * Return 0 if ok. + * Return -1 with errno set on error. + */ +static int +errlog(void) +{ + int fd[2]; + char buff[1024]; + FILE *f; + int ret = 0; + + if (pipe(fd) < 0) + return (-1); + switch (fork()) { + case -1: /* Error */ + return (-1); + case 0: /* Child */ + if ((f = fdopen(fd[READ_END], "r")) == NULL) { + syslog(LOG_ERR, "fdopen: %m"); + exit(EXIT_FAILURE); + } + (void)close(fd[WRITE_END]); + while (fgets(buff, sizeof(buff), f) != NULL) + syslog(LOG_ERR, "exec: %s", buff); + exit(EXIT_SUCCESS); + /* NOTREACHED */ + default: /* Parent */ + if (dup2(fd[WRITE_END], STDERR_FILENO) < 0) + ret = -1; + (void)close(fd[READ_END]); + (void)close(fd[WRITE_END]); + break; + } + return (ret); +} + +/* + * Parse the args string as a space-separated argument vector. + * If argv is not NULL, split the string into its constituent + * components, and set argv to point to the beginning of each + * string component; NULL-terminating argv. + * Return the number of string components. + */ +static int +parse_argv(char *args, char **argv) +{ + int count = 0; + char *p; + enum {WORD, SPACE} state = SPACE; + + for (p = args; *p; p++) + switch (state) { + case WORD: + if (isspace(*p)) { + if (argv) + *p = '\0'; + state = SPACE; + } + break; + case SPACE: + if (!isspace(*p)) { + if (argv) + argv[count] = p; + count++; + state = WORD; + } + } + if (argv) + argv[count] = NULL; + return (count); +} |