/* * Copyright (c) 2016 * Tama Communications Corporation * * This file is part of GNU GLOBAL. * * 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 3 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, see . */ #if !((defined(_WIN32) && !defined(__CYGWIN__)) || defined(__DJGPP__)) #ifdef HAVE_CONFIG_H #include #endif #include #include #include #ifdef STDC_HEADERS #include #endif #ifdef HAVE_UNISTD_H #include #endif #include "die.h" #include "pool.h" #include "secure_popen.h" #define ARGS 20 static POOL *pool; static char *argv[ARGS]; static int argc; /* * Secure popen does not use sh(1). So, it is more secure. */ /* * Constructing args * * secure_open_args(); * secure_add_args("find"); * secure_add_args("."); * secure_add_args("-type"); * secure_add_args("f"); * secure_add_args("-print"); * args = secure_close_args(); * * args -->[0] = "find" * [1] = "." * [2] = "-type" * [3] = "f" * [4] = "-print" * [5] = NULL */ void secure_open_args(void) { if (pool == NULL) pool = pool_open(); pool_reset(pool); argc = 0; } void secure_add_args(char *string) { argv[argc++] = pool_strdup(pool, string, 0); if (argc >= ARGS) die("secure_add_args: argv overflow."); } char ** secure_close_args() { argv[argc] = NULL; return argv; } /* * Secure substitution of popen(3) */ static pid_t pid; /** * secure_popen * * @param[in] command command (full path) * @param[in] type "r": read, "w", write * @return file descripter * * The process which can be invoked at the same time is restricted to only one. */ FILE * secure_popen(const char *command, const char *type, char **argv) { FILE *ip; int fd[2]; if (pipe(fd) < 0) return (NULL); pid = fork(); if (pid == 0) { /* child process */ if (*type == 'r') { close(fd[0]); if (dup2(fd[1], STDOUT_FILENO) < 0) die("dup2 failed."); } else { close(fd[1]); if (dup2(fd[0], STDIN_FILENO) < 0) die("dup2 failed."); } execvp(command, argv); die("cannot execute '%s'. (execvp failed)", command); } /* parent process */ if (pid < 0) die("fork failed."); if (*type == 'r') { close(fd[1]); ip = fdopen(fd[0], "r"); } else { close(fd[0]); ip = fdopen(fd[1], "w"); } if (ip == NULL) die("fdopen failed."); return ip; } int secure_pclose(FILE *ip) { int status, ppid; (void)fclose(ip); do { ppid = waitpid(pid, &status, 0); } while (ppid == -1 && errno == EINTR); return (ppid == -1 ? -1 : status); } #endif