2 * Copyright (C) 1005 Diomidis Spinellis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/syslog.h>
44 /* Usage conventions for the pipe's endpoints. */
48 static int errlog(void);
49 static int parse_argv(char *args, char **argv);
51 int portal_pipe(pcr, key, v, so, fdp)
52 struct portal_cred *pcr;
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];
67 /* Variables used to save the the caller's credentials. */
70 gid_t old_groups[NGROUPS_MAX];
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. */
76 else if (pcr->pcr_flag & FREAD) {
78 * The caller reads from the pipe,
79 * the spawned process writes to it.
81 caller_end = READ_END;
82 process_end = WRITE_END;
83 redirect_fd = STDOUT_FILENO;
84 } else if (pcr->pcr_flag & FWRITE) {
86 * The caller writes to the pipe,
87 * the spawned process reads from it.
89 caller_end = WRITE_END;
90 process_end = READ_END;
91 redirect_fd = STDIN_FILENO;
95 /* Get and check command line. */
97 strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0));
98 argc = parse_argv(pbuf, NULL);
102 /* Swap priviledges. */
104 if ((ngroups = getgroups(NGROUPS_MAX, old_groups)) < 0)
106 if (setgroups(pcr->pcr_ngroups, pcr->pcr_groups) < 0)
108 if (seteuid(pcr->pcr_uid) < 0)
111 /* Redirect and spawn the specified process. */
112 fd[READ_END] = fd[WRITE_END] = -1;
121 default: /* Parent */
122 (void)close(fd[process_end]);
125 argv = (char **)malloc((argc + 1) * sizeof(char *));
128 "malloc: failed to get space for %d pointers",
132 parse_argv(pbuf, argv);
134 if (dup2(fd[process_end], redirect_fd) < 0) {
135 syslog(LOG_ERR, "dup2: %m");
138 (void)close(fd[caller_end]);
139 (void)close(fd[process_end]);
141 syslog(LOG_ERR, "errlog: %m");
144 if (execv(argv[0], argv) < 0) {
145 syslog(LOG_ERR, "execv(%s): %m", argv[0]);
152 /* Re-establish our priviledges. */
153 if (seteuid(old_uid) < 0) {
155 syslog(LOG_ERR, "seteuid: %m");
157 if (setgroups(ngroups, old_groups) < 0) {
159 syslog(LOG_ERR, "setgroups: %m");
162 /* Set return fd value. */
164 *fdp = fd[caller_end];
166 for (i = 0; i < 2; i++)
176 * Redirect stderr to the system log.
178 * Return -1 with errno set on error.
194 if ((f = fdopen(fd[READ_END], "r")) == NULL) {
195 syslog(LOG_ERR, "fdopen: %m");
198 (void)close(fd[WRITE_END]);
199 while (fgets(buff, sizeof(buff), f) != NULL)
200 syslog(LOG_ERR, "exec: %s", buff);
203 default: /* Parent */
204 if (dup2(fd[WRITE_END], STDERR_FILENO) < 0)
206 (void)close(fd[READ_END]);
207 (void)close(fd[WRITE_END]);
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.
221 parse_argv(char *args, char **argv)
225 enum {WORD, SPACE} state = SPACE;
227 for (p = args; *p; p++)