Skip to content

Commit

Permalink
util: script: Amended protocol with the ability to convey a set of en…
Browse files Browse the repository at this point in the history
…vironment variables that are passed to the script.

The acceptable environment variables are selected using the -e parameter; others are ignored silently.
  • Loading branch information
stephanbosch committed May 23, 2017
1 parent 2dcb39c commit 262a9b6
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 11 deletions.
9 changes: 9 additions & 0 deletions src/lib-program-client/program-client-remote.c
Expand Up @@ -5,6 +5,7 @@
#include "ioloop.h"
#include "str.h"
#include "strescape.h"
#include "array.h"
#include "net.h"
#include "write-full.h"
#include "eacces-error.h"
Expand Down Expand Up @@ -215,6 +216,14 @@ void program_client_remote_connected(struct program_client *pclient)

str = t_str_new(1024);
str_append(str, PROGRAM_CLIENT_VERSION_STRING);
if (array_is_created(&pclient->envs)) {
const char *const *env;
array_foreach(&pclient->envs, env) {
str_append(str, "env_");
str_append_tabescaped(str, *env);
str_append_c(str, '\n');
}
}
if (prclient->noreply)
str_append(str, "noreply\n");
else
Expand Down
71 changes: 60 additions & 11 deletions src/util/script.c
Expand Up @@ -20,6 +20,7 @@
#define SCRIPT_READ_TIMEOUT_SECS 10

static ARRAY_TYPE(const_string) exec_args;
static const char **accepted_envs;

static void script_verify_version(const char *line)
{
Expand All @@ -32,7 +33,8 @@ static void script_verify_version(const char *line)


static void
exec_child(struct master_service_connection *conn, const char *const *args)
exec_child(struct master_service_connection *conn,
const char *const *args, const char *const *envs)
{
unsigned int i, socket_count;

Expand All @@ -59,17 +61,23 @@ exec_child(struct master_service_connection *conn, const char *const *args)
array_append_zero(&exec_args);

env_clean();
if (envs != NULL) {
for(; *envs != NULL; envs++)
env_put(*envs);
}

args = array_idx(&exec_args, 0);
execvp_const(args[0], args);
}

static bool client_exec_script(struct master_service_connection *conn)
{
ARRAY_TYPE(const_string) envs;
const char *const *args;
string_t *input;
void *buf;
size_t prev_size, scanpos;
bool header_complete = FALSE;
bool header_complete = FALSE, noreply = FALSE;
ssize_t ret;
int status;
pid_t pid;
Expand Down Expand Up @@ -144,23 +152,44 @@ static bool client_exec_script(struct master_service_connection *conn)

args = t_strsplit(str_c(input), "\n");
script_verify_version(*args); args++;
t_array_init(&envs, 16);
if (*args != NULL) {
const char *p;

if (strncmp(*args, "alarm=", 6) == 0) {
unsigned int seconds;
if (str_to_uint(*args + 6, &seconds) < 0)
i_fatal("invalid alarm option");
alarm(seconds);
args++;
}
while (strncmp(*args, "env_", 4) == 0) {
const char *envname, *env;

env = t_str_tabunescape(*args+4);
p = strchr(env, '=');
if (p == NULL)
i_fatal("invalid environment variable");
envname = t_strdup_until(*args+4, p);

if (str_array_find(accepted_envs, envname))
array_append(&envs, &env, 1);
args++;
}
if (strcmp(*args, "noreply") == 0) {
/* no need to fork and check exit status */
exec_child(conn, args + 1);
i_unreached();
noreply = TRUE;
}
if (**args == '\0')
i_fatal("empty options");
args++;
}
array_append_zero(&envs);

if (noreply) {
/* no need to fork and check exit status */
exec_child(conn, args, array_idx(&envs, 0));
i_unreached();
}

if ((pid = fork()) == (pid_t)-1) {
i_error("fork() failed: %m");
Expand All @@ -169,7 +198,7 @@ static bool client_exec_script(struct master_service_connection *conn)

if (pid == 0) {
/* child */
exec_child(conn, args);
exec_child(conn, args, array_idx(&envs, 0));
i_unreached();
}

Expand Down Expand Up @@ -210,15 +239,33 @@ static void client_connected(struct master_service_connection *conn)

int main(int argc, char *argv[])
{
ARRAY_TYPE(const_string) aenvs;
const char *binary;
int i;

master_service = master_service_init("script", 0, &argc, &argv, "+");
if (master_getopt(master_service) > 0)
return FATAL_DEFAULT;
const char *const *envs;
int c, i;

master_service = master_service_init("script", 0, &argc, &argv, "+e:");

t_array_init(&aenvs, 16);
while ((c = master_getopt(master_service)) > 0) {
switch (c) {
case 'e':
envs = t_strsplit_spaces(optarg,", \t");
while (*envs != NULL) {
array_append(&aenvs, envs, 1);
envs++;
}
break;
default:
return FATAL_DEFAULT;
}
}
argc -= optind;
argv += optind;

array_append_zero(&aenvs);
accepted_envs = p_strarray_dup(default_pool, array_idx(&aenvs, 0));

master_service_init_log(master_service, "script: ");
if (argv[0] == NULL)
i_fatal("Missing script path");
Expand All @@ -242,6 +289,8 @@ int main(int argc, char *argv[])
}

master_service_run(master_service, client_connected);
array_free(&exec_args);
i_free(accepted_envs);
master_service_deinit(&master_service);
return 0;
}

0 comments on commit 262a9b6

Please sign in to comment.