bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainenstatic void script_verify_version(const char *line)
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?)");
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Boschexec_child(struct master_service_connection *conn,
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch const char *const *args, const char *const *envs)
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 Sirainenstatic bool client_exec_script(struct master_service_connection *conn)
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch bool header_complete = FALSE, noreply = FALSE;
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen /* Input contains:
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen VERSION .. <lf>
7439b55b88ec777baf00b8aa24a99017ab4ecb01Timo Sirainen [alarm=<secs> <lf>]
95d41d210790d6c544537d2ef10c5f3cf86055e2Timo Sirainen "noreply" | "-" (or anything really) <lf>
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.
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen buf = buffer_append_space_unsafe(input, IO_BLOCK_SIZE);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* peek in socket input buffer */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen ret = recv(conn->fd, buf, IO_BLOCK_SIZE, MSG_PEEK);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen script_verify_version(t_strcut(str_c(input), '\n'));
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("recv(MSG_PEEK) failed: disconnected");
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* scan for final \n\n */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen end = CONST_PTR_OFFSET(input->data, prev_size + ret);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen scanpos = pos - (const unsigned char *)input->data;
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 i_fatal("recv() failed: size of definitive recv() differs from peek");
b5b44e6c99e62ba5f7600ac72c26327a1f8dfb8dTimo Sirainen /* drop the last two LFs */
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch const char *p;
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch /* no need to fork and check exit status */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen /* check script exit status */
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("Script terminated abnormally, exit status %d", (int)ret);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_error("Script terminated abnormally, signal %d", WTERMSIG(status));
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("Script stopped, signal %d", WSTOPSIG(status));
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen i_fatal("Script terminated abnormally, return status %d", status);
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainenstatic void client_connected(struct master_service_connection *conn)
2d3731908f924bc8a2b7887a712cc033e618c998Timo Sirainen response[0] = client_exec_script(conn) ? '+' : '-';
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch master_service = master_service_init("script", 0, &argc, &argv, "+e:");
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch while ((c = master_getopt(master_service)) > 0) {
7e993ece468916599df2feb3d4c64a91c69cedf8Stephan Bosch accepted_envs = p_strarray_dup(default_pool, array_idx(&aenvs, 0));
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_init_log(master_service, "script: ");
816d20be0cf95fc4eb1a8aa716639e73b8ba525eMartti Rannanjärvi restrict_access_by_env(RESTRICT_ACCESS_FLAG_ALLOW_ROOT, NULL);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen master_service_set_service_count(master_service, 1);
cbfdc79faac95adc8a3f76ee2216d3fea0c19826Timo Sirainen binary = t_strconcat(PKG_LIBEXECDIR"/", argv[0], NULL);