Skip to content

Commit 308ddcd

Browse files
committed
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
1 parent d7dbc74 commit 308ddcd

File tree

5 files changed

+252
-2
lines changed

5 files changed

+252
-2
lines changed

usr.sbin/mount_portalfs/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
PROG= mount_portalfs
55
SRCS= mount_portalfs.c activate.c conf.c getmntopts.c pt_conf.c \
6-
pt_exec.c pt_file.c pt_tcp.c pt_tcplisten.c
6+
pt_exec.c pt_file.c pt_pipe.c pt_tcp.c pt_tcplisten.c
77
MAN= mount_portalfs.8
88

99
MOUNT= ${.CURDIR}/../../sbin/mount

usr.sbin/mount_portalfs/portal.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
tcplisten/ tcplisten tcplisten/
44
tcp/ tcp tcp/
55
fs/ file fs/
6-
pipe/ pipe
6+
pipe/ pipe pipe/
77
foo/ exec ./bar bar baz

usr.sbin/mount_portalfs/portald.h

+2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ extern int portal_exec(struct portal_cred *,
6767
char *key, char **v, int so, int *fdp);
6868
extern int portal_file(struct portal_cred *,
6969
char *key, char **v, int so, int *fdp);
70+
extern int portal_pipe(struct portal_cred *,
71+
char *key, char **v, int so, int *fdp);
7072
extern int portal_tcp(struct portal_cred *,
7173
char *key, char **v, int so, int *fdp);
7274
extern int portal_tcplisten(struct portal_cred *,

usr.sbin/mount_portalfs/pt_conf.c

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
4343
provider providers[] = {
4444
{ "exec", portal_exec },
4545
{ "file", portal_file },
46+
{ "pipe", portal_pipe },
4647
{ "tcp", portal_tcp },
4748
{ "tcplisten", portal_tcplisten },
4849
{ 0, 0 }

usr.sbin/mount_portalfs/pt_pipe.c

+247
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
/*-
2+
* Copyright (C) 1005 Diomidis Spinellis. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16+
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19+
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22+
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23+
* SUCH DAMAGE.
24+
*
25+
*/
26+
27+
#include <sys/cdefs.h>
28+
__FBSDID("$FreeBSD$");
29+
30+
#include <ctype.h>
31+
#include <errno.h>
32+
#include <fcntl.h>
33+
#include <stdio.h>
34+
#include <stdlib.h>
35+
#include <string.h>
36+
#include <unistd.h>
37+
38+
#include <sys/types.h>
39+
#include <sys/param.h>
40+
#include <sys/syslog.h>
41+
42+
#include "portald.h"
43+
44+
/* Usage conventions for the pipe's endpoints. */
45+
#define READ_END 0
46+
#define WRITE_END 1
47+
48+
static int errlog(void);
49+
static int parse_argv(char *args, char **argv);
50+
51+
int portal_pipe(pcr, key, v, so, fdp)
52+
struct portal_cred *pcr;
53+
char *key;
54+
char **v;
55+
int so;
56+
int *fdp;
57+
{
58+
int fd[2]; /* Pipe endpoints. */
59+
int caller_end; /* The pipe end we will use. */
60+
int process_end; /* The pipe end the spawned process will use. */
61+
int redirect_fd; /* The fd to redirect on the spawned process. */
62+
char pbuf[MAXPATHLEN];
63+
int error = 0;
64+
int i;
65+
char **argv;
66+
int argc;
67+
/* Variables used to save the the caller's credentials. */
68+
uid_t old_uid;
69+
int ngroups;
70+
gid_t old_groups[NGROUPS_MAX];
71+
72+
/* Validate open mode, and assign roles. */
73+
if ((pcr->pcr_flag & FWRITE) && (pcr->pcr_flag & FREAD))
74+
/* Don't allow both on a single fd. */
75+
return (EINVAL);
76+
else if (pcr->pcr_flag & FREAD) {
77+
/*
78+
* The caller reads from the pipe,
79+
* the spawned process writes to it.
80+
*/
81+
caller_end = READ_END;
82+
process_end = WRITE_END;
83+
redirect_fd = STDOUT_FILENO;
84+
} else if (pcr->pcr_flag & FWRITE) {
85+
/*
86+
* The caller writes to the pipe,
87+
* the spawned process reads from it.
88+
*/
89+
caller_end = WRITE_END;
90+
process_end = READ_END;
91+
redirect_fd = STDIN_FILENO;
92+
} else
93+
return (EINVAL);
94+
95+
/* Get and check command line. */
96+
pbuf[0] = '/';
97+
strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0));
98+
argc = parse_argv(pbuf, NULL);
99+
if (argc == 0)
100+
return (ENOENT);
101+
102+
/* Swap priviledges. */
103+
old_uid = geteuid();
104+
if ((ngroups = getgroups(NGROUPS_MAX, old_groups)) < 0)
105+
return (errno);
106+
if (setgroups(pcr->pcr_ngroups, pcr->pcr_groups) < 0)
107+
return (errno);
108+
if (seteuid(pcr->pcr_uid) < 0)
109+
return (errno);
110+
111+
/* Redirect and spawn the specified process. */
112+
fd[READ_END] = fd[WRITE_END] = -1;
113+
if (pipe(fd) < 0) {
114+
error = errno;
115+
goto done;
116+
}
117+
switch (fork()) {
118+
case -1: /* Error */
119+
error = errno;
120+
break;
121+
default: /* Parent */
122+
(void)close(fd[process_end]);
123+
break;
124+
case 0: /* Child */
125+
argv = (char **)malloc((argc + 1) * sizeof(char *));
126+
if (argv == 0) {
127+
syslog(LOG_ALERT,
128+
"malloc: failed to get space for %d pointers",
129+
argc + 1);
130+
exit(EXIT_FAILURE);
131+
}
132+
parse_argv(pbuf, argv);
133+
134+
if (dup2(fd[process_end], redirect_fd) < 0) {
135+
syslog(LOG_ERR, "dup2: %m");
136+
exit(EXIT_FAILURE);
137+
}
138+
(void)close(fd[caller_end]);
139+
(void)close(fd[process_end]);
140+
if (errlog() < 0) {
141+
syslog(LOG_ERR, "errlog: %m");
142+
exit(EXIT_FAILURE);
143+
}
144+
if (execv(argv[0], argv) < 0) {
145+
syslog(LOG_ERR, "execv(%s): %m", argv[0]);
146+
exit(EXIT_FAILURE);
147+
}
148+
/* NOTREACHED */
149+
}
150+
151+
done:
152+
/* Re-establish our priviledges. */
153+
if (seteuid(old_uid) < 0) {
154+
error = errno;
155+
syslog(LOG_ERR, "seteuid: %m");
156+
}
157+
if (setgroups(ngroups, old_groups) < 0) {
158+
error = errno;
159+
syslog(LOG_ERR, "setgroups: %m");
160+
}
161+
162+
/* Set return fd value. */
163+
if (error == 0)
164+
*fdp = fd[caller_end];
165+
else {
166+
for (i = 0; i < 2; i++)
167+
if (fd[i] >= 0)
168+
(void)close(fd[i]);
169+
*fdp = -1;
170+
}
171+
172+
return (error);
173+
}
174+
175+
/*
176+
* Redirect stderr to the system log.
177+
* Return 0 if ok.
178+
* Return -1 with errno set on error.
179+
*/
180+
static int
181+
errlog(void)
182+
{
183+
int fd[2];
184+
char buff[1024];
185+
FILE *f;
186+
int ret = 0;
187+
188+
if (pipe(fd) < 0)
189+
return (-1);
190+
switch (fork()) {
191+
case -1: /* Error */
192+
return (-1);
193+
case 0: /* Child */
194+
if ((f = fdopen(fd[READ_END], "r")) == NULL) {
195+
syslog(LOG_ERR, "fdopen: %m");
196+
exit(EXIT_FAILURE);
197+
}
198+
(void)close(fd[WRITE_END]);
199+
while (fgets(buff, sizeof(buff), f) != NULL)
200+
syslog(LOG_ERR, "exec: %s", buff);
201+
exit(EXIT_SUCCESS);
202+
/* NOTREACHED */
203+
default: /* Parent */
204+
if (dup2(fd[WRITE_END], STDERR_FILENO) < 0)
205+
ret = -1;
206+
(void)close(fd[READ_END]);
207+
(void)close(fd[WRITE_END]);
208+
break;
209+
}
210+
return (ret);
211+
}
212+
213+
/*
214+
* Parse the args string as a space-separated argument vector.
215+
* If argv is not NULL, split the string into its constituent
216+
* components, and set argv to point to the beginning of each
217+
* string component; NULL-terminating argv.
218+
* Return the number of string components.
219+
*/
220+
static int
221+
parse_argv(char *args, char **argv)
222+
{
223+
int count = 0;
224+
char *p;
225+
enum {WORD, SPACE} state = SPACE;
226+
227+
for (p = args; *p; p++)
228+
switch (state) {
229+
case WORD:
230+
if (isspace(*p)) {
231+
if (argv)
232+
*p = '\0';
233+
state = SPACE;
234+
}
235+
break;
236+
case SPACE:
237+
if (!isspace(*p)) {
238+
if (argv)
239+
argv[count] = p;
240+
count++;
241+
state = WORD;
242+
}
243+
}
244+
if (argv)
245+
argv[count] = NULL;
246+
return (count);
247+
}

0 commit comments

Comments
 (0)