Mercurial > dovecot > core-2.2
view src/util/script.c @ 12607:40f668d36547
script: Root permissions weren't being dropped before executing the script.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 30 Jan 2011 17:51:17 +0200 |
parents | 54bcc1728a43 |
children | baa0314ed610 |
line wrap: on
line source
/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "str.h" #include "env-util.h" #include "execv-const.h" #include "restrict-access.h" #include "master-interface.h" #include "master-service.h" #include <stdlib.h> #include <unistd.h> #define SCRIPT_MAJOR_VERSION 2 #define SCRIPT_READ_TIMEOUT_SECS 10 static ARRAY_TYPE(const_string) exec_args; static void script_verify_version(const char *line) { if (line == NULL || !version_string_verify(line, "script", SCRIPT_MAJOR_VERSION)) { i_fatal("Client not compatible with this binary " "(connecting to wrong socket?)"); } } static void client_connected(struct master_service_connection *conn) { const unsigned char *end; const char *const *args; buffer_t *input; void *buf; unsigned int i, socket_count; size_t prev_size; ssize_t ret; net_set_nonblock(conn->fd, FALSE); input = buffer_create_dynamic(pool_datastack_create(), IO_BLOCK_SIZE); /* Input contains: VERSION .. <lf> arg 1 <lf> arg 2 <lf> ... <lf> [data] */ alarm(SCRIPT_READ_TIMEOUT_SECS); do { prev_size = input->used; buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE); ret = read(conn->fd, buf, IO_BLOCK_SIZE); if (ret <= 0) { buffer_set_used_size(input, prev_size); if (strchr(str_c(input), '\n') != NULL) script_verify_version(t_strcut(str_c(input), '\t')); if (ret < 0) i_fatal("read() failed: %m"); else i_fatal("read() failed: disconnected"); } buffer_set_used_size(input, prev_size + ret); end = CONST_PTR_OFFSET(input->data, input->used); } while (!(end[-1] == '\n' && (input->used == 1 || end[-2] == '\n'))); /* drop the last LF */ buffer_set_used_size(input, input->used - 1); args = t_strsplit(str_c(input), "\n"); script_verify_version(*args); for (args++; *args != NULL; args++) array_append(&exec_args, args, 1); (void)array_append_space(&exec_args); /* close all fds */ socket_count = master_service_get_socket_count(master_service); for (i = 0; i < socket_count; i++) { if (close(MASTER_LISTEN_FD_FIRST + i) < 0) i_error("close(listener) failed: %m"); } if (close(MASTER_STATUS_FD) < 0) i_error("close(status) failed: %m"); if (write(conn->fd, "1\n", 2) != 2) i_error("write() failed: %m"); if (dup2(conn->fd, STDIN_FILENO) < 0 || dup2(conn->fd, STDOUT_FILENO) < 0) i_error("dup2() failed: %m"); if (close(conn->fd) < 0) i_error("close() failed: %m"); env_clean(); args = array_idx(&exec_args, 0); execvp_const(args[0], args); } int main(int argc, char *argv[]) { const char *binary; int i; master_service = master_service_init("script", 0, &argc, &argv, "+"); if (master_getopt(master_service) > 0) return FATAL_DEFAULT; argc -= optind; argv += optind; master_service_init_log(master_service, "script: "); restrict_access_by_env(NULL, FALSE); restrict_access_allow_coredumps(TRUE); master_service_init_finish(master_service); master_service_set_service_count(master_service, 1); if (argv[0] == NULL) i_fatal("Missing script path"); if (argv[0][0] == '/') binary = argv[0]; else binary = t_strconcat(PKG_LIBEXECDIR"/", argv[0], NULL); i_array_init(&exec_args, argc + 16); array_append(&exec_args, &binary, 1); for (i = 1; i < argc; i++) { const char *arg = argv[i]; array_append(&exec_args, &arg, 1); } master_service_run(master_service, client_connected); master_service_deinit(&master_service); return 0; }