Signed-off-by: Rémy Oudompheng <remy@archlinux.org> --- src/pacman/callback.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 74 insertions(+), 1 deletions(-) diff --git a/src/pacman/callback.c b/src/pacman/callback.c index 1ff9a47..06f161c 100644 --- a/src/pacman/callback.c +++ b/src/pacman/callback.c @@ -25,6 +25,7 @@ #include <string.h> #include <sys/time.h> #include <sys/types.h> /* off_t */ +#include <sys/wait.h> /* waitpid */ #include <unistd.h> #include <wchar.h> @@ -689,7 +690,79 @@ void cb_log(pmloglevel_t level, const char *fmt, va_list args) /* Callback to check signatures with an external command */ int cb_checksig(const char *path, const pmpgpsig_t *sig) { - return 0; + int ret = 0; + int retval; + int childpid; + char *parsedcmd; + int pipefd[2]; + + if(!config->checksigcommand) { + return -1; + } + + parsedcmd = strdup(config->checksigcommand); + /* replace all occurrences of %f with the filename */ + if(strstr(parsedcmd, "%f")) { + char *tempcmd = strreplace(parsedcmd, "%f", path); + free(parsedcmd); + parsedcmd = tempcmd; + } + + /* execute the parsed command via /bin/sh -c */ + pipe(pipefd); + childpid = fork(); + + if (childpid < 0) { + pm_printf(PM_LOG_ERROR, _("running ChecksigCommand: fork failed!\n")); + ret = -1; + goto cleanup; + } else if (childpid == 0) { + /* we are in the child */ + close(pipefd[1]); + /* read from the pipe */ + dup2(pipefd[0], 0); + pm_printf(PM_LOG_DEBUG, "child: running command: %s\n", parsedcmd); + if (execl("/bin/sh", "/bin/sh", "-c", parsedcmd, NULL) == -1) + exit(127); + } else { + /* we are still in pacman */ + close(pipefd[0]); + size_t remaining; + const char *signature = alpm_pgpsig_get_raw(sig, &remaining); + if (! signature) { + close(pipefd[1]); + ret = -1; + goto wait; + } + while(remaining > 0) { + /* write signature into pipe */ + ssize_t written = write(pipefd[1], signature, remaining); + if (written < 0) { + pm_printf(PM_LOG_ERROR, _("running ChecksigCommand: broken pipe!\n")); + ret = -1; + break; + } + signature += written; + remaining -= written; + } + close(pipefd[1]); + } + +wait: + waitpid(childpid, &retval, 0); + + if(!WIFEXITED(retval)) { + /* exited abnormally */ + pm_printf(PM_LOG_DEBUG, "ChecksigCommand exited abnormally " + "status (%d,%d)\n", retval >> 8, retval & 0xff); + ret = -1; + } else { + ret = (WEXITSTATUS(retval) == 0) ? 0 : 1; + } + +cleanup: + free(parsedcmd); + return ret; } /* vim: set ts=2 sw=2 noet: */ -- 1.7.4.4