bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "lib.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "array.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "str.h"
bcba310035d85064fe8fb9b4b1c85b07ac518022Stephan Bosch#include "strescape.h"
7f945ad00fd50dbbbe09dc2e79e0d8d24f917052Timo Sirainen#include "env-util.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "execv-const.h"
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen#include "write-full.h"
00c45bda5196d5bcdeaec132075c29dc6be714d5Timo Sirainen#include "restrict-access.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "master-interface.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include "master-service.h"
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#include <unistd.h>
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen#include <sys/types.h>
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen#include <sys/wait.h>
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen#include <sys/socket.h>
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
b383ed51d75bce0f69f126bc4ff7192985ca30f2Stephan Bosch#define SCRIPT_MAJOR_VERSION 4
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen#define SCRIPT_READ_TIMEOUT_SECS 10
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainenstatic ARRAY_TYPE(const_string) exec_args;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Boschstatic const char **accepted_envs;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainenstatic void script_verify_version(const char *line)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen{
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (line == NULL ||
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen !version_string_verify(line, "script", SCRIPT_MAJOR_VERSION)) {
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_fatal("Client not compatible with this binary "
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen "(connecting to wrong socket?)");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen}
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainenstatic void
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Boschexec_child(struct master_service_connection *conn,
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch const char *const *args, const char *const *envs)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen{
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen unsigned int i, socket_count;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (dup2(conn->fd, STDIN_FILENO) < 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("dup2() failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (dup2(conn->fd, STDOUT_FILENO) < 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("dup2() failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* close all fds */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen socket_count = master_service_get_socket_count(master_service);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen for (i = 0; i < socket_count; i++) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (close(MASTER_LISTEN_FD_FIRST + i) < 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("close(listener) failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (close(MASTER_STATUS_FD) < 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("close(status) failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (close(conn->fd) < 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("close(conn->fd) failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
bcba310035d85064fe8fb9b4b1c85b07ac518022Stephan Bosch for (; *args != NULL; args++) {
bcba310035d85064fe8fb9b4b1c85b07ac518022Stephan Bosch const char *arg = t_str_tabunescape(*args);
bcba310035d85064fe8fb9b4b1c85b07ac518022Stephan Bosch array_append(&exec_args, &arg, 1);
bcba310035d85064fe8fb9b4b1c85b07ac518022Stephan Bosch }
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&exec_args);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen env_clean();
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch if (envs != NULL) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch for(; *envs != NULL; envs++)
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch env_put(*envs);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch }
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen args = array_idx(&exec_args, 0);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen execvp_const(args[0], args);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen}
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainenstatic bool client_exec_script(struct master_service_connection *conn)
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen{
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch ARRAY_TYPE(const_string) envs;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen const char *const *args;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen string_t *input;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen void *buf;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen size_t prev_size, scanpos;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch bool header_complete = FALSE, noreply = FALSE;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen ssize_t ret;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen int status;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen pid_t pid;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen net_set_nonblock(conn->fd, FALSE);
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi input = t_buffer_create(IO_BLOCK_SIZE);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen /* Input contains:
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen VERSION .. <lf>
7439b55b88ec777baf00b8aa24a99017ab4ecb01Timo Sirainen [alarm=<secs> <lf>]
95d41d210790d6c544537d2ef10c5f3cf86055e2Timo Sirainen "noreply" | "-" (or anything really) <lf>
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen arg 1 <lf>
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen arg 2 <lf>
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen ...
bd4cc8e98cc894d716942ec3173bc4d237dc43b1Timo Sirainen <lf>
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen DATA
7439b55b88ec777baf00b8aa24a99017ab4ecb01Timo Sirainen
95d41d210790d6c544537d2ef10c5f3cf86055e2Timo Sirainen This is quite a horrible protocol. If alarm is specified, it MUST be
95d41d210790d6c544537d2ef10c5f3cf86055e2Timo Sirainen before "noreply". If "noreply" isn't given, something other string
95d41d210790d6c544537d2ef10c5f3cf86055e2Timo Sirainen (typically "-") must be given which is eaten away.
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen */
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen alarm(SCRIPT_READ_TIMEOUT_SECS);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen scanpos = 1;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen while (!header_complete) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen const unsigned char *pos, *end;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen prev_size = input->used;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* peek in socket input buffer */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (ret <= 0) {
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen buffer_set_used_size(input, prev_size);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (strchr(str_c(input), '\n') != NULL)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen script_verify_version(t_strcut(str_c(input), '\n'));
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (ret < 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("recv(MSG_PEEK) failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("recv(MSG_PEEK) failed: disconnected");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* scan for final \n\n */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen pos = CONST_PTR_OFFSET(input->data, scanpos);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen end = CONST_PTR_OFFSET(input->data, prev_size + ret);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen for (; pos < end; pos++) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (pos[-1] == '\n' && pos[0] == '\n') {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen header_complete = TRUE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen pos++;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen break;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen }
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen scanpos = pos - (const unsigned char *)input->data;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* read data for real (up to and including \n\n) */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen ret = recv(conn->fd, buf, scanpos-prev_size, 0);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (prev_size+ret != scanpos) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (ret < 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("recv() failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (ret == 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("recv() failed: disconnected");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("recv() failed: size of definitive recv() differs from peek");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen buffer_set_used_size(input, scanpos);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
8656ae1d89e3576902376658cd8657d30748414fTimo Sirainen alarm(0);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
b5b44e6c99e62ba5f7600ac72c26327a1f8dfb8dTimo Sirainen /* drop the last two LFs */
b5b44e6c99e62ba5f7600ac72c26327a1f8dfb8dTimo Sirainen buffer_set_used_size(input, scanpos-2);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen args = t_strsplit(str_c(input), "\n");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen script_verify_version(*args); args++;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch t_array_init(&envs, 16);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (*args != NULL) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch const char *p;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch
8656ae1d89e3576902376658cd8657d30748414fTimo Sirainen if (strncmp(*args, "alarm=", 6) == 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch unsigned int seconds;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch if (str_to_uint(*args + 6, &seconds) < 0)
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch i_fatal("invalid alarm option");
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch alarm(seconds);
8656ae1d89e3576902376658cd8657d30748414fTimo Sirainen args++;
8656ae1d89e3576902376658cd8657d30748414fTimo Sirainen }
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch while (strncmp(*args, "env_", 4) == 0) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch const char *envname, *env;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch env = t_str_tabunescape(*args+4);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch p = strchr(env, '=');
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch if (p == NULL)
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch i_fatal("invalid environment variable");
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch envname = t_strdup_until(*args+4, p);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch if (str_array_find(accepted_envs, envname))
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch array_append(&envs, &env, 1);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch args++;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch }
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (strcmp(*args, "noreply") == 0) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch noreply = TRUE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
b5b44e6c99e62ba5f7600ac72c26327a1f8dfb8dTimo Sirainen if (**args == '\0')
4f68fa8a117642e2c134a29d8e35569bce6c3158Timo Sirainen i_fatal("empty options");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen args++;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch array_append_zero(&envs);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch if (noreply) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch /* no need to fork and check exit status */
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch exec_child(conn, args, array_idx(&envs, 0));
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch i_unreached();
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if ((pid = fork()) == (pid_t)-1) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("fork() failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen return FALSE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (pid == 0) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* child */
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch exec_child(conn, args, array_idx(&envs, 0));
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_unreached();
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen }
bd4cc8e98cc894d716942ec3173bc4d237dc43b1Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* parent */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* check script exit status */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (waitpid(pid, &status, 0) < 0) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("waitpid() failed: %m");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen return FALSE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen } else if (WIFEXITED(status)) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen ret = WEXITSTATUS(status);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (ret != 0) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("Script terminated abnormally, exit status %d", (int)ret);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen return FALSE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen } else if (WIFSIGNALED(status)) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("Script terminated abnormally, signal %d", WTERMSIG(status));
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen return FALSE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen } else if (WIFSTOPPED(status)) {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("Script stopped, signal %d", WSTOPSIG(status));
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen return FALSE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen } else {
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("Script terminated abnormally, return status %d", status);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen return FALSE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen }
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen return TRUE;
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen}
bd4cc8e98cc894d716942ec3173bc4d237dc43b1Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainenstatic void client_connected(struct master_service_connection *conn)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen{
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen char response[2];
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen response[0] = client_exec_script(conn) ? '+' : '-';
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen response[1] = '\n';
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen if (write_full(conn->fd, &response, 2) < 0)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("write(response) failed: %m");
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen}
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainenint main(int argc, char *argv[])
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen{
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch ARRAY_TYPE(const_string) aenvs;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen const char *binary;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch const char *const *envs;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch int c, i;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch master_service = master_service_init("script", 0, &argc, &argv, "+e:");
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch t_array_init(&aenvs, 16);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch while ((c = master_getopt(master_service)) > 0) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch switch (c) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch case 'e':
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch envs = t_strsplit_spaces(optarg,", \t");
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch while (*envs != NULL) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch array_append(&aenvs, envs, 1);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch envs++;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch }
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch break;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch default:
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch return FATAL_DEFAULT;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch }
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen argc -= optind;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen argv += optind;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch array_append_zero(&aenvs);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch accepted_envs = p_strarray_dup(default_pool, array_idx(&aenvs, 0));
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_init_log(master_service, "script: ");
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen if (argv[0] == NULL)
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen i_fatal("Missing script path");
816d20be0cf95fc4eb1a8aa716639e73b8ba525eMartti Rannanjärvi restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
00c45bda5196d5bcdeaec132075c29dc6be714d5Timo Sirainen restrict_access_allow_coredumps(TRUE);
00c45bda5196d5bcdeaec132075c29dc6be714d5Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_init_finish(master_service);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_set_service_count(master_service, 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen if (argv[0][0] == '/')
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen binary = argv[0];
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen else
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen binary = t_strconcat(PKG_LIBEXECDIR"/", argv[0], NULL);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen i_array_init(&exec_args, argc + 16);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen array_append(&exec_args, &binary, 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen for (i = 1; i < argc; i++) {
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen const char *arg = argv[i];
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen array_append(&exec_args, &arg, 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen }
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_run(master_service, client_connected);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch array_free(&exec_args);
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch i_free(accepted_envs);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_deinit(&master_service);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen return 0;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen}