167 lines
4.4 KiB
C
167 lines
4.4 KiB
C
|
/* extpipe.c 08-Aug-97 */
|
||
|
/* (C)opyright (C) 1993,1996 Martin Stover, Marburg, Germany
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
*/
|
||
|
|
||
|
#include "net.h"
|
||
|
#include "extpipe.h"
|
||
|
|
||
|
static char **build_argv(char *buf, int bufsize, char *command)
|
||
|
/* routine returns **argv for use with execv routines */
|
||
|
/* buf will contain the path component */
|
||
|
{
|
||
|
int len = strlen(command);
|
||
|
int offset = ((len+4) / 4) * 4; /* aligned offset for **argv */
|
||
|
int components = (bufsize - offset) / 4;
|
||
|
if (components > 1) { /* minimal argv[0] + NULL */
|
||
|
char **argv = (char **)(buf+offset);
|
||
|
char **pp = argv;
|
||
|
char *p = buf;
|
||
|
char c;
|
||
|
int i=0;
|
||
|
--components;
|
||
|
memcpy(buf, command, len);
|
||
|
memset(buf+len, 0, bufsize - len);
|
||
|
*pp = p;
|
||
|
while ((0 != (c = *p++)) && i < components) {
|
||
|
if (c == 32 || c == '\t') {
|
||
|
*(p-1) = '\0';
|
||
|
if (*p != 32 && *p != '\t') {
|
||
|
*(++pp)=p;
|
||
|
i++;
|
||
|
}
|
||
|
} else if (!i && c == '/') { /* here i must get argv[0] */
|
||
|
*pp=p;
|
||
|
}
|
||
|
}
|
||
|
XDPRINTF((5, 0, "build_argv, path='%s'", buf));
|
||
|
pp=argv;
|
||
|
while (*pp) {
|
||
|
XDPRINTF((5, 0, "build_argv, argv='%s'", *pp));
|
||
|
pp++;
|
||
|
}
|
||
|
return(argv);
|
||
|
}
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void close_piped(int piped[3][2])
|
||
|
{
|
||
|
int j=3;
|
||
|
while (j--) {
|
||
|
int k=2;
|
||
|
while (k--) {
|
||
|
if (piped[j][k] > -1){
|
||
|
close(piped[j][k]);
|
||
|
piped[j][k] = -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int x_popen(char *command, int uid, int gid, FILE_PIPE *fp)
|
||
|
{
|
||
|
int piped[3][2];
|
||
|
int lpid=-1;
|
||
|
int j=3;
|
||
|
char buf[300];
|
||
|
char **argv=build_argv(buf, sizeof(buf), command);
|
||
|
if (argv == NULL) return(-1);
|
||
|
while (j--){
|
||
|
int k=2;
|
||
|
while(k--) piped[j][k] = -1;
|
||
|
}
|
||
|
if (! (pipe(&piped[0][0]) > -1 && pipe(&piped[1][0]) > -1
|
||
|
&& pipe(&piped[2][0]) > -1 && (lpid=fork()) > -1)) {
|
||
|
close_piped(piped);
|
||
|
return(-1);
|
||
|
}
|
||
|
if (lpid == 0) { /* Child */
|
||
|
signal(SIGTERM, SIG_DFL);
|
||
|
signal(SIGQUIT, SIG_DFL);
|
||
|
signal(SIGINT, SIG_DFL);
|
||
|
signal(SIGPIPE, SIG_DFL);
|
||
|
signal(SIGHUP, SIG_DFL);
|
||
|
j=3;
|
||
|
while(j--) close(j);
|
||
|
j=3;
|
||
|
while(j--) {
|
||
|
int x = (j) ? 0 : 1;
|
||
|
int x_ = (j) ? 1 : 0;
|
||
|
close(piped[j][x] );
|
||
|
dup2( piped[j][x_], j);
|
||
|
close(piped[j][x_] );
|
||
|
}
|
||
|
if (uid > -1 || gid > -1) {
|
||
|
seteuid(0);
|
||
|
if (gid > -1) setgid(gid);
|
||
|
if (uid > -1) setuid(uid);
|
||
|
if (gid > -1) setegid(gid);
|
||
|
if (uid > -1) seteuid(uid);
|
||
|
}
|
||
|
execvp(buf, argv);
|
||
|
exit(1); /* Never reached I hope */
|
||
|
}
|
||
|
j=-1;
|
||
|
while (++j < 3) {
|
||
|
int x = (j) ? 0 : 1;
|
||
|
int x_ = (j) ? 1 : 0;
|
||
|
close(piped[j][x_]);
|
||
|
piped [j][x_] = -1;
|
||
|
fp->fds[j] = piped[j][x];
|
||
|
}
|
||
|
return(lpid);
|
||
|
}
|
||
|
|
||
|
int ext_pclose(FILE_PIPE *fp)
|
||
|
{
|
||
|
int status=-1;
|
||
|
void (*intsave) (int) = signal(SIGINT, SIG_IGN);
|
||
|
void (*quitsave)(int) = signal(SIGQUIT, SIG_IGN);
|
||
|
void (*hupsave) (int) = signal(SIGHUP, SIG_IGN);
|
||
|
int j = 3;
|
||
|
while (j--) close(fp->fds[j]);
|
||
|
if (fp->command_pid != waitpid(fp->command_pid, &status, 0)) {
|
||
|
kill(fp->command_pid, SIGTERM);
|
||
|
waitpid(fp->command_pid, &status, 0);
|
||
|
}
|
||
|
kill(fp->command_pid, SIGKILL);
|
||
|
signal(SIGINT, intsave);
|
||
|
signal(SIGQUIT, quitsave);
|
||
|
signal(SIGHUP, hupsave);
|
||
|
xfree(fp);
|
||
|
return(status);
|
||
|
}
|
||
|
|
||
|
FILE_PIPE *ext_popen(char *command, int uid, int gid)
|
||
|
{
|
||
|
FILE_PIPE *fp=(FILE_PIPE*) xcmalloc(sizeof(FILE_PIPE));
|
||
|
void (*intsave) (int) = signal(SIGINT, SIG_IGN);
|
||
|
void (*quitsave)(int) = signal(SIGQUIT, SIG_IGN);
|
||
|
void (*hupsave) (int) = signal(SIGHUP, SIG_IGN);
|
||
|
if ((fp->command_pid = x_popen(command, uid, gid, fp)) < 0) {
|
||
|
xfree(fp);
|
||
|
fp=NULL;
|
||
|
XDPRINTF((1, 0x10, "ext_popen failed:uid=%d, gid=%d,command='%s'",
|
||
|
uid, gid, command));
|
||
|
}
|
||
|
signal(SIGINT, intsave);
|
||
|
signal(SIGQUIT, quitsave);
|
||
|
signal(SIGHUP, hupsave);
|
||
|
return(fp);
|
||
|
}
|