Skip to content

Commit

Permalink
Run cf-agent for localhost requests on the runagent.socket
Browse files Browse the repository at this point in the history
cf-execd should run cf-agent locally if 'localhost' (or a
localhost IP address) agent run is requested via the
runagent.socket.

Ticket: ENT-7090
Changelog: cf-execd now executes cf-agent for "localhost" requests via the runagent.socket
  • Loading branch information
vpodzime committed May 28, 2021
1 parent edfcc62 commit 39294a4
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 22 deletions.
112 changes: 95 additions & 17 deletions cf-execd/cf-execd-runagent.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,84 @@
#include <pipes.h>
#include <alloc.h>
#include <file_lib.h>
#include <string_lib.h>
#include <known_dirs.h>

#include <cf-execd-runagent.h>

static inline bool StringIsLocalhostIP(const char *str)
{
assert(str != NULL);

const char *c = str;
if (*(c++) != '1')
{
return false;
}
if (*(c++) != '2')
{
return false;
}
if (*(c++) != '7')
{
return false;
}
if (*(c++) != '.')
{
return false;
}

short n_dgts = 0;
while ((*c != '\0') && (*c != '.'))
{
if (!isdigit(*(c++)))
{
return false;
}
n_dgts++;
}
if ((n_dgts > 3) || (*(c++) != '.'))
{
return false;
}

n_dgts = 0;
while ((*c != '\0') && (*c != '.'))
{
if (!isdigit(*(c++)))
{
return false;
}
n_dgts++;
}
if ((n_dgts > 3) || (*(c++) != '.'))
{
return false;
}

n_dgts = 0;
while (*c != '\0')
{
if (!isdigit(*(c++)))
{
return false;
}
n_dgts++;
}
if (n_dgts > 3)
{
return false;
}

return true;
}

/**
* Handle request to run cf-runagent.
*
* @note Expected to be called from a forked child process (blocks and forks).
*/
void HandleRunagentRequest(int conn_fd)
void HandleRunagentRequest(int conn_fd, const char *local_run_command)
{
FILE *conn_file = fdopen(conn_fd, "r+");
if (conn_file == NULL)
Expand Down Expand Up @@ -81,44 +148,55 @@ void HandleRunagentRequest(int conn_fd)
}

/* TODO: '--raw' for just getting output from cf-runagent directly? */
const char *tool = NULL;
char *command;
xasprintf(&command, "%s%ccf-runagent -b -H %s", GetBinDir(), FILE_SEPARATOR, request);

if (StringEqual(request, "localhost") || StringIsLocalhostIP(request))
{
tool = "cf-agent";
command = xstrdup(local_run_command);
}
else
{
tool = "cf-runagent";
xasprintf(&command, "%s%ccf-runagent -b -H %s", GetBinDir(), FILE_SEPARATOR, request);
}
free(request);

FILE *runagent_output = cf_popen(command, "r", true);
FILE *run_agent_output = cf_popen(command, "r", true);
free(command);

if (runagent_output == NULL)
if (run_agent_output == NULL)
{
Log(LOG_LEVEL_ERR, "Failed to start cf-runagent and connect to its output");
fprintf(conn_file, "{\"error\": \"Failed to start cf-runagent and connect to its output\"}");
Log(LOG_LEVEL_ERR, "Failed to start %s and connect to its output", tool);
fprintf(conn_file, "{\"error\": \"Failed to start %s and connect to its output\"}", tool);
fclose(conn_file);
return;
}

Buffer *collected_output = BufferNewWithCapacity(1024);
char output_buffer[CF_BUFSIZE];
size_t read_bytes = fread(output_buffer, 1, sizeof(output_buffer), runagent_output);
size_t read_bytes = fread(output_buffer, 1, sizeof(output_buffer), run_agent_output);
while (read_bytes > 0)
{
BufferAppend(collected_output, output_buffer, read_bytes);
read_bytes = fread(output_buffer, 1, sizeof(output_buffer), runagent_output);
read_bytes = fread(output_buffer, 1, sizeof(output_buffer), run_agent_output);
}
if (!feof(runagent_output))
if (!feof(run_agent_output))
{
Log(LOG_LEVEL_ERR, "Failed to read output from cf-runagent");
fprintf(conn_file, "{\"error\": \"Failed to read output from cf-runagent\"}");
cf_pclose(runagent_output);
Log(LOG_LEVEL_ERR, "Failed to read output from %s", tool);
fprintf(conn_file, "{\"error\": \"Failed to read output from %s\"}", tool);
cf_pclose(run_agent_output);
fclose(conn_file);
return;
}
BufferAppendChar(collected_output, '\0');

int runagent_ret = cf_pclose(runagent_output);
if (runagent_ret == -1)
int run_agent_ret = cf_pclose(run_agent_output);
if (run_agent_ret == -1)
{
Log(LOG_LEVEL_ERR, "Failed to wait for the cf-runagent process to terminate");
fprintf(conn_file, "{\"error\": \"Failed to wait for the cf-runagent process to terminate\"}");
Log(LOG_LEVEL_ERR, "Failed to wait for the %s process to terminate", tool);
fprintf(conn_file, "{\"error\": \"Failed to wait for the %s process to terminate\"}", tool);
fclose(conn_file);
return;
}
Expand All @@ -129,7 +207,7 @@ void HandleRunagentRequest(int conn_fd)
JsonEncodeStringWriter(BufferData(collected_output), json_writer);
written = WriterWrite(json_writer, "\",\n");
assert(written > 0);
written = WriterWriteF(json_writer, "\"exit_code\": %d\n", runagent_ret);
written = WriterWriteF(json_writer, "\"exit_code\": %d\n", run_agent_ret);
assert(written > 0);
written = WriterWrite(json_writer, "}\n");
assert(written > 0);
Expand Down
2 changes: 1 addition & 1 deletion cf-execd/cf-execd-runagent.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
#ifndef CFENGINE_CF_EXECD_RUNAGENT_H
#define CFENGINE_CF_EXECD_RUNAGENT_H

void HandleRunagentRequest(int conn_fd);
void HandleRunagentRequest(int conn_fd, const char *local_run_command);

#endif
10 changes: 6 additions & 4 deletions cf-execd/cf-execd.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,8 @@ static inline bool UsingRunagentSocket()
*
* @return Whether to terminate (skip any further actions) or not.
*/
static bool HandleRequestsOrSleep(time_t seconds, const char *reason, int runagent_socket)
static bool HandleRequestsOrSleep(time_t seconds, const char *reason,
int runagent_socket, const char *local_run_command)
{
if (IsPendingTermination())
{
Expand Down Expand Up @@ -482,7 +483,7 @@ static bool HandleRequestsOrSleep(time_t seconds, const char *reason, int runage
{
/* child */
signal(SIGPIPE, SIG_DFL);
HandleRunagentRequest(data_socket);
HandleRunagentRequest(data_socket, local_run_command);
_exit(EXIT_SUCCESS);
}
else if (pid == -1)
Expand Down Expand Up @@ -529,7 +530,7 @@ static void CFExecdMainLoop(EvalContext *ctx, Policy **policy, GenericAgentConfi
if (ScheduleRun(ctx, policy, config, execd_config, exec_config))
{
terminate = HandleRequestsOrSleep((*execd_config)->splay_time, "splay time",
runagent_socket);
runagent_socket, (*execd_config)->local_run_command);
if (terminate)
{
break;
Expand All @@ -543,7 +544,8 @@ static void CFExecdMainLoop(EvalContext *ctx, Policy **policy, GenericAgentConfi
}
}
/* 1 Minute resolution is enough */
terminate = HandleRequestsOrSleep(CFPULSETIME, "pulse time", runagent_socket);
terminate = HandleRequestsOrSleep(CFPULSETIME, "pulse time", runagent_socket,
(*execd_config)->local_run_command);
if (terminate)
{
break;
Expand Down
28 changes: 28 additions & 0 deletions cf-execd/execd-config.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include <eval_context.h>
#include <conversion.h>
#include <string_lib.h>
#include <mod_common.h> /* CFS_CONTROLBODY, SERVER_CONTROL_CFRUNCOMMAND */
#include <expand.h> /* ExpandScalar() */

/* Get a number in the interval [0, 1) for a calculation of a pseudo-random delay */
static double GetSplay(void)
Expand Down Expand Up @@ -116,6 +118,31 @@ ExecdConfig *ExecdConfigNew(const EvalContext *ctx, const Policy *policy)
}
}

/* We need to pull the 'cfruncommand' value from 'body control server' for
* local run-agent requests. */
constraints = ControlBodyConstraints(policy, AGENT_TYPE_SERVER);
if (constraints != NULL)
{
const size_t length = SeqLength(constraints);
for (size_t i = 0; i < length; i++)
{
Constraint *cp = SeqAt(constraints, i);

if (!IsDefinedClass(ctx, cp->classes))
{
continue;
}
if (StringEqual(cp->lval, CFS_CONTROLBODY[SERVER_CONTROL_CFRUNCOMMAND].lval))
{
assert(cp->rval.type == RVAL_TYPE_SCALAR);
execd_config->local_run_command = ExpandScalar(ctx, NULL, NULL,
RvalScalarValue(cp->rval),
NULL);
break;
}
}
}

return execd_config;
}

Expand All @@ -126,6 +153,7 @@ void ExecdConfigDestroy(ExecdConfig *execd_config)
free(execd_config->log_facility);
StringSetDestroy(execd_config->schedule);
StringSetDestroy(execd_config->runagent_allow_users);
free(execd_config->local_run_command);
}
free(execd_config);
}
1 change: 1 addition & 0 deletions cf-execd/execd-config.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef struct ExecdConfig
int splay_time;
char *log_facility;
StringSet *runagent_allow_users;
char *local_run_command;
} ExecdConfig;

ExecdConfig *ExecdConfigNew(const EvalContext *ctx, const Policy *policy);
Expand Down

0 comments on commit 39294a4

Please sign in to comment.