From b8a95a56699b48572f61a59905455ad2e77430d2 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Fri, 7 Sep 2012 15:33:50 -0600 Subject: [PATCH 1/4] Expand environment variables used as configuration values. --- src/conf-yaml-loader.c | 274 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 272 insertions(+), 2 deletions(-) diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index b90a29af463..d37e81c40ef 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -24,6 +24,7 @@ */ #include +#include #include "suricata-common.h" #include "conf.h" #include "util-debug.h" @@ -64,6 +65,117 @@ Mangle(char *string) return; } +/** + * \brief Get the compiled pcre for environment variable expansion. + * + * \retval The compiled pcre + */ +static pcre * +GetEnvVarPcre(void) +{ + static pcre *envvar_pcre = NULL; + const char *error; + int erroroffset; + + static const char pattern[] = "\\$\\{" + "(" "[^\\$\\{\\}:-]*" ")" + "(:-(" "[^\\$\\{\\}:-]*" "))?" + "\\}"; + + if (envvar_pcre == NULL) { + envvar_pcre = pcre_compile(pattern, 0, &error, &erroroffset, NULL); + if (envvar_pcre == NULL) { + fprintf(stderr, "ERROR: Failed to compile pcre: %s", error); + exit(1); + } + } + + return envvar_pcre; +} + +/** + * \brief Perform environment variable expansion on the provided string. + * + * \param string The string to perform environment variable expansion. + * + * \retval A new string with environment variables expanded, only if expansion + * took place. Otherwise NULL is returned. As this is a new string it + * must be free'd by the caller. + */ +static char * +ExpandEnvVar(char *string) +{ + const char *var_name; + const char *var_val = NULL; + int var_val_len = 0; + int segment_start; + int segment_end; + const char *default_val = NULL; + char *new_str; + int new_str_len; + int ovector[12]; + + int match = pcre_exec(GetEnvVarPcre(), NULL, string, strlen(string), 0, 0, + ovector, 12); + if (match < 2) { + return NULL; + } + segment_start = ovector[0]; + segment_end = ovector[1]; + + if (pcre_get_substring(string, ovector, match, 1, &var_name) < 0) { + fprintf(stderr, "pcre failure\n"); + exit(1); + } + + /* Do we also have a default? */ + if (match == 4) { + if (pcre_get_substring(string, ovector, match, 3, &default_val) < 0) { + fprintf(stderr, "pcre failure\n"); + exit(1); + } + } + + /* Get the environment variable, using the optional default if the + * environment variable is not set. */ + if (NULL != (var_val = getenv(var_name))) { + var_val_len = strlen(var_val); + } + else if (default_val != NULL) { + var_val = default_val; + var_val_len = strlen(var_val); + } + + /* Calculate the length of the new string including termination + * and then allocate it. */ + + new_str_len = strlen(string) - (segment_end - segment_start) + + var_val_len + 1; + BUG_ON(new_str_len < 1); + new_str = SCCalloc(1, new_str_len); + + /* Build the new string. */ + if (segment_start) + strncat(new_str, string, segment_start); + if (var_val != NULL) + strncat(new_str, var_val, var_val_len); + if (strlen(string) > (size_t)segment_end) + strcat(new_str, string + segment_end); + + pcre_free_substring(var_name); + if (default_val != NULL) + pcre_free_substring(default_val); + + /* Recurse to expand other variables. */ + char *new_new_str = ExpandEnvVar(new_str); + if (new_new_str != NULL) { + SCFree(new_str); + new_str = new_new_str; + } + + return new_str; +} + /** * \brief Parse a YAML layer. * @@ -118,7 +230,8 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) if (seq_node->name == NULL) return -1; snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++); - seq_node->val = SCStrdup(value); + if (NULL == (seq_node->val = ExpandEnvVar(value))) + seq_node->val = SCStrdup(value); TAILQ_INSERT_TAIL(&parent->head, seq_node, next); } else { @@ -161,7 +274,8 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) if (node->allow_override) { if (node->val != NULL) SCFree(node->val); - node->val = SCStrdup(value); + if (NULL == (node->val = ExpandEnvVar(value))) + node->val = SCStrdup(value); } state = CONF_KEY; } @@ -519,6 +633,159 @@ libhtp:\n\ return 1; } +static int +ConfYamlEnvVarExpandTest(void) +{ + char *new; + const char *old_foo = getenv("FOO"); + const char *old_bar = getenv("BAR"); + + setenv("FOO", "bar", 1); + setenv("BAR", "foo", 1); + + if (ExpandEnvVar("something") != NULL) + return 0; + if (ExpandEnvVar("$something") != NULL) + return 0; + if (ExpandEnvVar("${something") != NULL) + return 0; + + new = ExpandEnvVar("${}"); + if (new == NULL || strcmp(new, "") != 0) { + return 0; + } + SCFree(new); + + new = ExpandEnvVar("${FOO}"); + if (new == NULL || strcmp(new, "bar") != 0) { + return 0; + } + SCFree(new); + + new = ExpandEnvVar("pre${FOO}"); + if (new == NULL || strcmp(new, "prebar") != 0) { + return 0; + } + SCFree(new); + + new = ExpandEnvVar("${FOO}post"); + if (new == NULL || strcmp(new, "barpost") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "barpost", new); + return 0; + } + SCFree(new); + + new = ExpandEnvVar("pre${FOO}post"); + if (new == NULL || strcmp(new, "prebarpost") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "prebarpost", new); + return 0; + } + SCFree(new); + + new = ExpandEnvVar("pre${NOFOO}post"); + if (new == NULL || strcmp(new, "prepost") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "prepost", new); + return 0; + } + SCFree(new); + + new = ExpandEnvVar("${FOO}${BAR}"); + if (new == NULL || strcmp(new, "barfoo") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "barfoo", new); + return 0; + } + SCFree(new); + + new = ExpandEnvVar("${FOO}${BAR}${FOOBAR}"); + if (new == NULL || strcmp(new, "barfoo") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "barfoo", new); + return 0; + } + SCFree(new); + + new = ExpandEnvVar("${USER}"); + if (new == NULL || strcmp(new, getenv("USER")) != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", getenv("USER"), new); + return 0; + } + SCFree(new); + + unsetenv("FOO"); + unsetenv("BAR"); + + if (old_foo != NULL) + setenv("FOO", old_foo, 1); + if (old_bar != NULL) + setenv("BAR", old_bar, 1); + + return 1; +} + +static int +ConfYamlEnvVarExpandTestWithDefaultValue(void) +{ + char *new; + + new = ExpandEnvVar("${FOO:-foo}"); + if (new == NULL || strcmp(new, "foo") != 0) { + fprintf(stderr, "%d: expected '%s', got '%s'\n", __LINE__, "foo", new); + return 0; + } + SCFree(new); + + new = ExpandEnvVar("pre${FOO:-foo}post"); + if (new == NULL || strcmp(new, "prefoopost") != 0) { + fprintf(stderr, "%d: expected '%s', got '%s'\n", __LINE__, "foo", new); + return 0; + } + SCFree(new); + + const char *old_foo = getenv("FOO"); + const char *old_bar = getenv("BAR"); + + setenv("FOO", "bar", 1); + setenv("BAR", "foo", 1); + + new = ExpandEnvVar("${FOO:-foo}"); + if (new == NULL || strcmp(new, "bar") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); + return 0; + } + SCFree(new); + + new = ExpandEnvVar("${FOO:-${BAR}}"); + if (new == NULL || strcmp(new, "bar") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); + return 0; + } + SCFree(new); + + new = ExpandEnvVar("${NOFOO:-${BAR}}"); + if (new == NULL || strcmp(new, "foo") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); + return 0; + } + SCFree(new); + + /* A bit silly now... */ + new = ExpandEnvVar("${NOFOO:-${NOBAR:-nofoobar}}"); + if (new == NULL || strcmp(new, "nofoobar") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); + return 0; + } + SCFree(new); + + unsetenv("FOO"); + unsetenv("BAR"); + + if (old_foo != NULL) + setenv("FOO", old_foo, 1); + if (old_bar != NULL) + setenv("BAR", old_bar, 1); + + return 1; +} + #endif /* UNITTESTS */ void @@ -531,5 +798,8 @@ ConfYamlRegisterTests(void) UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest, 1); UtRegisterTest("ConfYamlSecondLevelSequenceTest", ConfYamlSecondLevelSequenceTest, 1); + UtRegisterTest("ConfYamlEnvVarExpandTest", ConfYamlEnvVarExpandTest, 1); + UtRegisterTest("ConfYamlEnvVarExpandTestWithDefaultValue", + ConfYamlEnvVarExpandTestWithDefaultValue, 1); #endif /* UNITTESTS */ } From 2155788d16f1d9d1576cdd9b0abfe2b9ecf72fb4 Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 31 Oct 2012 10:24:23 -0600 Subject: [PATCH 2/4] Move variable expansion code to the generic configuration API. --- src/conf-yaml-loader.c | 271 +---------------------------------------- src/conf.c | 266 ++++++++++++++++++++++++++++++++++++++++ src/conf.h | 2 + 3 files changed, 270 insertions(+), 269 deletions(-) diff --git a/src/conf-yaml-loader.c b/src/conf-yaml-loader.c index d37e81c40ef..80c6409e8fe 100644 --- a/src/conf-yaml-loader.c +++ b/src/conf-yaml-loader.c @@ -65,117 +65,6 @@ Mangle(char *string) return; } -/** - * \brief Get the compiled pcre for environment variable expansion. - * - * \retval The compiled pcre - */ -static pcre * -GetEnvVarPcre(void) -{ - static pcre *envvar_pcre = NULL; - const char *error; - int erroroffset; - - static const char pattern[] = "\\$\\{" - "(" "[^\\$\\{\\}:-]*" ")" - "(:-(" "[^\\$\\{\\}:-]*" "))?" - "\\}"; - - if (envvar_pcre == NULL) { - envvar_pcre = pcre_compile(pattern, 0, &error, &erroroffset, NULL); - if (envvar_pcre == NULL) { - fprintf(stderr, "ERROR: Failed to compile pcre: %s", error); - exit(1); - } - } - - return envvar_pcre; -} - -/** - * \brief Perform environment variable expansion on the provided string. - * - * \param string The string to perform environment variable expansion. - * - * \retval A new string with environment variables expanded, only if expansion - * took place. Otherwise NULL is returned. As this is a new string it - * must be free'd by the caller. - */ -static char * -ExpandEnvVar(char *string) -{ - const char *var_name; - const char *var_val = NULL; - int var_val_len = 0; - int segment_start; - int segment_end; - const char *default_val = NULL; - char *new_str; - int new_str_len; - int ovector[12]; - - int match = pcre_exec(GetEnvVarPcre(), NULL, string, strlen(string), 0, 0, - ovector, 12); - if (match < 2) { - return NULL; - } - segment_start = ovector[0]; - segment_end = ovector[1]; - - if (pcre_get_substring(string, ovector, match, 1, &var_name) < 0) { - fprintf(stderr, "pcre failure\n"); - exit(1); - } - - /* Do we also have a default? */ - if (match == 4) { - if (pcre_get_substring(string, ovector, match, 3, &default_val) < 0) { - fprintf(stderr, "pcre failure\n"); - exit(1); - } - } - - /* Get the environment variable, using the optional default if the - * environment variable is not set. */ - if (NULL != (var_val = getenv(var_name))) { - var_val_len = strlen(var_val); - } - else if (default_val != NULL) { - var_val = default_val; - var_val_len = strlen(var_val); - } - - /* Calculate the length of the new string including termination - * and then allocate it. */ - - new_str_len = strlen(string) - (segment_end - segment_start) + - var_val_len + 1; - BUG_ON(new_str_len < 1); - new_str = SCCalloc(1, new_str_len); - - /* Build the new string. */ - if (segment_start) - strncat(new_str, string, segment_start); - if (var_val != NULL) - strncat(new_str, var_val, var_val_len); - if (strlen(string) > (size_t)segment_end) - strcat(new_str, string + segment_end); - - pcre_free_substring(var_name); - if (default_val != NULL) - pcre_free_substring(default_val); - - /* Recurse to expand other variables. */ - char *new_new_str = ExpandEnvVar(new_str); - if (new_new_str != NULL) { - SCFree(new_str); - new_str = new_new_str; - } - - return new_str; -} - /** * \brief Parse a YAML layer. * @@ -230,7 +119,7 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) if (seq_node->name == NULL) return -1; snprintf(seq_node->name, DEFAULT_NAME_LEN, "%d", seq_idx++); - if (NULL == (seq_node->val = ExpandEnvVar(value))) + if (NULL == (seq_node->val = ConfExpandEnvVar(value))) seq_node->val = SCStrdup(value); TAILQ_INSERT_TAIL(&parent->head, seq_node, next); } @@ -274,7 +163,7 @@ ConfYamlParse(yaml_parser_t *parser, ConfNode *parent, int inseq) if (node->allow_override) { if (node->val != NULL) SCFree(node->val); - if (NULL == (node->val = ExpandEnvVar(value))) + if (NULL == (node->val = ConfExpandEnvVar(value))) node->val = SCStrdup(value); } state = CONF_KEY; @@ -633,159 +522,6 @@ libhtp:\n\ return 1; } -static int -ConfYamlEnvVarExpandTest(void) -{ - char *new; - const char *old_foo = getenv("FOO"); - const char *old_bar = getenv("BAR"); - - setenv("FOO", "bar", 1); - setenv("BAR", "foo", 1); - - if (ExpandEnvVar("something") != NULL) - return 0; - if (ExpandEnvVar("$something") != NULL) - return 0; - if (ExpandEnvVar("${something") != NULL) - return 0; - - new = ExpandEnvVar("${}"); - if (new == NULL || strcmp(new, "") != 0) { - return 0; - } - SCFree(new); - - new = ExpandEnvVar("${FOO}"); - if (new == NULL || strcmp(new, "bar") != 0) { - return 0; - } - SCFree(new); - - new = ExpandEnvVar("pre${FOO}"); - if (new == NULL || strcmp(new, "prebar") != 0) { - return 0; - } - SCFree(new); - - new = ExpandEnvVar("${FOO}post"); - if (new == NULL || strcmp(new, "barpost") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "barpost", new); - return 0; - } - SCFree(new); - - new = ExpandEnvVar("pre${FOO}post"); - if (new == NULL || strcmp(new, "prebarpost") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "prebarpost", new); - return 0; - } - SCFree(new); - - new = ExpandEnvVar("pre${NOFOO}post"); - if (new == NULL || strcmp(new, "prepost") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "prepost", new); - return 0; - } - SCFree(new); - - new = ExpandEnvVar("${FOO}${BAR}"); - if (new == NULL || strcmp(new, "barfoo") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "barfoo", new); - return 0; - } - SCFree(new); - - new = ExpandEnvVar("${FOO}${BAR}${FOOBAR}"); - if (new == NULL || strcmp(new, "barfoo") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "barfoo", new); - return 0; - } - SCFree(new); - - new = ExpandEnvVar("${USER}"); - if (new == NULL || strcmp(new, getenv("USER")) != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", getenv("USER"), new); - return 0; - } - SCFree(new); - - unsetenv("FOO"); - unsetenv("BAR"); - - if (old_foo != NULL) - setenv("FOO", old_foo, 1); - if (old_bar != NULL) - setenv("BAR", old_bar, 1); - - return 1; -} - -static int -ConfYamlEnvVarExpandTestWithDefaultValue(void) -{ - char *new; - - new = ExpandEnvVar("${FOO:-foo}"); - if (new == NULL || strcmp(new, "foo") != 0) { - fprintf(stderr, "%d: expected '%s', got '%s'\n", __LINE__, "foo", new); - return 0; - } - SCFree(new); - - new = ExpandEnvVar("pre${FOO:-foo}post"); - if (new == NULL || strcmp(new, "prefoopost") != 0) { - fprintf(stderr, "%d: expected '%s', got '%s'\n", __LINE__, "foo", new); - return 0; - } - SCFree(new); - - const char *old_foo = getenv("FOO"); - const char *old_bar = getenv("BAR"); - - setenv("FOO", "bar", 1); - setenv("BAR", "foo", 1); - - new = ExpandEnvVar("${FOO:-foo}"); - if (new == NULL || strcmp(new, "bar") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); - return 0; - } - SCFree(new); - - new = ExpandEnvVar("${FOO:-${BAR}}"); - if (new == NULL || strcmp(new, "bar") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); - return 0; - } - SCFree(new); - - new = ExpandEnvVar("${NOFOO:-${BAR}}"); - if (new == NULL || strcmp(new, "foo") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); - return 0; - } - SCFree(new); - - /* A bit silly now... */ - new = ExpandEnvVar("${NOFOO:-${NOBAR:-nofoobar}}"); - if (new == NULL || strcmp(new, "nofoobar") != 0) { - fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); - return 0; - } - SCFree(new); - - unsetenv("FOO"); - unsetenv("BAR"); - - if (old_foo != NULL) - setenv("FOO", old_foo, 1); - if (old_bar != NULL) - setenv("BAR", old_bar, 1); - - return 1; -} - #endif /* UNITTESTS */ void @@ -798,8 +534,5 @@ ConfYamlRegisterTests(void) UtRegisterTest("ConfYamlBadYamlVersionTest", ConfYamlBadYamlVersionTest, 1); UtRegisterTest("ConfYamlSecondLevelSequenceTest", ConfYamlSecondLevelSequenceTest, 1); - UtRegisterTest("ConfYamlEnvVarExpandTest", ConfYamlEnvVarExpandTest, 1); - UtRegisterTest("ConfYamlEnvVarExpandTestWithDefaultValue", - ConfYamlEnvVarExpandTestWithDefaultValue, 1); #endif /* UNITTESTS */ } diff --git a/src/conf.c b/src/conf.c index bccdbc2be6c..f1943f896e0 100644 --- a/src/conf.c +++ b/src/conf.c @@ -773,8 +773,119 @@ char *ConfLoadCompleteIncludePath(char *file) return path; } +/** + * \brief Get the compiled pcre for environment variable expansion. + * + * This compiles the regular expression used in variable expansion and + * caches it for re-user. + * + * \retval The compiled pcre + */ +static pcre * +ConfGetEnvVarPcre(void) +{ + static pcre *envvar_pcre = NULL; + const char *error; + int erroroffset; + + static const char pattern[] = "\\$\\{" + "(" "[^\\$\\{\\}:-]*" ")" + "(:-(" "[^\\$\\{\\}:-]*" "))?" + "\\}"; + + if (envvar_pcre == NULL) { + envvar_pcre = pcre_compile(pattern, 0, &error, &erroroffset, NULL); + if (envvar_pcre == NULL) { + fprintf(stderr, "ERROR: Failed to compile pcre: %s", error); + exit(1); + } + } + + return envvar_pcre; +} + +/** + * \brief Perform environment variable expansion on the provided string. + * + * \param string The string to perform environment variable expansion. + * + * \retval A new string with environment variables expanded, only if expansion + * took place. Otherwise NULL is returned. As this is a new string it + * must be free'd by the caller. + */ +char * +ConfExpandEnvVar(char *string) +{ + const char *var_name; + const char *var_val = NULL; + int var_val_len = 0; + int segment_start; + int segment_end; + const char *default_val = NULL; + char *new_str; + int new_str_len; + int ovector[12]; + + int match = pcre_exec(ConfGetEnvVarPcre(), NULL, string, strlen(string), 0, + 0, ovector, 12); + if (match < 2) { + return NULL; + } + segment_start = ovector[0]; + segment_end = ovector[1]; + + if (pcre_get_substring(string, ovector, match, 1, &var_name) < 0) { + fprintf(stderr, "pcre failure\n"); + exit(1); + } + + /* Do we also have a default? */ + if (match == 4) { + if (pcre_get_substring(string, ovector, match, 3, &default_val) < 0) { + fprintf(stderr, "pcre failure\n"); + exit(1); + } + } + + /* Get the environment variable, using the optional default if the + * environment variable is not set. */ + if (NULL != (var_val = getenv(var_name))) { + var_val_len = strlen(var_val); + } + else if (default_val != NULL) { + var_val = default_val; + var_val_len = strlen(var_val); + } + /* Calculate the length of the new string including termination + * and then allocate it. */ + + new_str_len = strlen(string) - (segment_end - segment_start) + + var_val_len + 1; + BUG_ON(new_str_len < 1); + new_str = SCCalloc(1, new_str_len); + + /* Build the new string. */ + if (segment_start) + strncat(new_str, string, segment_start); + if (var_val != NULL) + strncat(new_str, var_val, var_val_len); + if (strlen(string) > (size_t)segment_end) + strcat(new_str, string + segment_end); + + pcre_free_substring(var_name); + if (default_val != NULL) + pcre_free_substring(default_val); + + /* Recurse to expand other variables. */ + char *new_new_str = ConfExpandEnvVar(new_str); + if (new_new_str != NULL) { + SCFree(new_str); + new_str = new_new_str; + } + return new_str; +} #ifdef UNITTESTS @@ -1194,6 +1305,158 @@ ConfSetTest(void) return 1; } +static int +ConfEnvVarExpandTest(void) +{ + char *new; + const char *old_foo = getenv("FOO"); + const char *old_bar = getenv("BAR"); + + setenv("FOO", "bar", 1); + setenv("BAR", "foo", 1); + + if (ConfExpandEnvVar("something") != NULL) + return 0; + if (ConfExpandEnvVar("$something") != NULL) + return 0; + if (ConfExpandEnvVar("${something") != NULL) + return 0; + + new = ConfExpandEnvVar("${}"); + if (new == NULL || strcmp(new, "") != 0) { + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("${FOO}"); + if (new == NULL || strcmp(new, "bar") != 0) { + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("pre${FOO}"); + if (new == NULL || strcmp(new, "prebar") != 0) { + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("${FOO}post"); + if (new == NULL || strcmp(new, "barpost") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "barpost", new); + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("pre${FOO}post"); + if (new == NULL || strcmp(new, "prebarpost") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "prebarpost", new); + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("pre${NOFOO}post"); + if (new == NULL || strcmp(new, "prepost") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "prepost", new); + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("${FOO}${BAR}"); + if (new == NULL || strcmp(new, "barfoo") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "barfoo", new); + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("${FOO}${BAR}${FOOBAR}"); + if (new == NULL || strcmp(new, "barfoo") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "barfoo", new); + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("${USER}"); + if (new == NULL || strcmp(new, getenv("USER")) != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", getenv("USER"), new); + return 0; + } + SCFree(new); + + unsetenv("FOO"); + unsetenv("BAR"); + + if (old_foo != NULL) + setenv("FOO", old_foo, 1); + if (old_bar != NULL) + setenv("BAR", old_bar, 1); + + return 1; +} + +static int +ConfEnvVarExpandTestWithDefaultValue(void) +{ + char *new; + + new = ConfExpandEnvVar("${FOO:-foo}"); + if (new == NULL || strcmp(new, "foo") != 0) { + fprintf(stderr, "%d: expected '%s', got '%s'\n", __LINE__, "foo", new); + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("pre${FOO:-foo}post"); + if (new == NULL || strcmp(new, "prefoopost") != 0) { + fprintf(stderr, "%d: expected '%s', got '%s'\n", __LINE__, "foo", new); + return 0; + } + SCFree(new); + + const char *old_foo = getenv("FOO"); + const char *old_bar = getenv("BAR"); + + setenv("FOO", "bar", 1); + setenv("BAR", "foo", 1); + + new = ConfExpandEnvVar("${FOO:-foo}"); + if (new == NULL || strcmp(new, "bar") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("${FOO:-${BAR}}"); + if (new == NULL || strcmp(new, "bar") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); + return 0; + } + SCFree(new); + + new = ConfExpandEnvVar("${NOFOO:-${BAR}}"); + if (new == NULL || strcmp(new, "foo") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); + return 0; + } + SCFree(new); + + /* A bit silly now... */ + new = ConfExpandEnvVar("${NOFOO:-${NOBAR:-nofoobar}}"); + if (new == NULL || strcmp(new, "nofoobar") != 0) { + fprintf(stderr, "expected '%s', got '%s'\n", "foo", new); + return 0; + } + SCFree(new); + + unsetenv("FOO"); + unsetenv("BAR"); + + if (old_foo != NULL) + setenv("FOO", old_foo, 1); + if (old_bar != NULL) + setenv("BAR", old_bar, 1); + + return 1; +} void ConfRegisterTests(void) @@ -1211,6 +1474,9 @@ ConfRegisterTests(void) UtRegisterTest("ConfGetChildValueWithDefaultTest", ConfGetChildValueWithDefaultTest, 1); UtRegisterTest("ConfGetChildValueIntWithDefaultTest", ConfGetChildValueIntWithDefaultTest, 1); UtRegisterTest("ConfGetChildValueBoolWithDefaultTest", ConfGetChildValueBoolWithDefaultTest, 1); + UtRegisterTest("ConfEnvVarExpandTest", ConfEnvVarExpandTest, 1); + UtRegisterTest("ConfEnvVarExpandTestWithDefaultValue", + ConfEnvVarExpandTestWithDefaultValue, 1); } #endif /* UNITTESTS */ diff --git a/src/conf.h b/src/conf.h index c9a089f771b..09d203f4d29 100644 --- a/src/conf.h +++ b/src/conf.h @@ -85,4 +85,6 @@ int ConfGetChildValueIntWithDefault(ConfNode *base, ConfNode *dflt, char *name, int ConfGetChildValueBoolWithDefault(ConfNode *base, ConfNode *dflt, char *name, int *val); char *ConfLoadCompleteIncludePath(char *); +char *ConfExpandEnvVar(char *string); + #endif /* ! __CONF_H__ */ From f8d4917a17fc443dee6c48604eb932ab2d1f7e3a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Wed, 31 Oct 2012 10:28:58 -0600 Subject: [PATCH 3/4] Provide example usage of variable expansion. --- suricata.yaml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/suricata.yaml.in b/suricata.yaml.in index 7d8fd671bf5..3a93842c227 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -825,7 +825,7 @@ ipfw: # Set the default rule path here to search for the files. # if not set, it will look at the current working dir -default-rule-path: @e_sysconfdir@rules +default-rule-path: ${SURICATA_RULE_PATH:-@e_sysconfdir@rules} rule-files: - botcc.rules - ciarmy.rules From 362918160c5ba2dcb113a8a54f3e2ae27089d67a Mon Sep 17 00:00:00 2001 From: Jason Ish Date: Tue, 22 Oct 2013 12:18:48 -0600 Subject: [PATCH 4/4] Check SCCalloc return value; use strlcat instead of strncat/strcat. --- src/conf.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/conf.c b/src/conf.c index f1943f896e0..3a7541f4122 100644 --- a/src/conf.c +++ b/src/conf.c @@ -814,22 +814,33 @@ ConfGetEnvVarPcre(void) * must be free'd by the caller. */ char * -ConfExpandEnvVar(char *string) +ConfExpandEnvVar(char *input) { + char *string = NULL; const char *var_name; const char *var_val = NULL; int var_val_len = 0; int segment_start; int segment_end; const char *default_val = NULL; - char *new_str; + char *pre_string = NULL; + char *post_string = NULL; + char *new_str = NULL; int new_str_len; int ovector[12]; + + /* Make a copy of the input string as we're destructive. */ + string = strdup(input); + if (unlikely(string == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, + "Error allocating memory for variable expansion"); + exit(EXIT_FAILURE); + } int match = pcre_exec(ConfGetEnvVarPcre(), NULL, string, strlen(string), 0, 0, ovector, 12); if (match < 2) { - return NULL; + goto end; } segment_start = ovector[0]; segment_end = ovector[1]; @@ -864,18 +875,26 @@ ConfExpandEnvVar(char *string) var_val_len + 1; BUG_ON(new_str_len < 1); new_str = SCCalloc(1, new_str_len); + if (unlikely(new_str == NULL)) { + SCLogError(SC_ERR_MEM_ALLOC, + "Error allocating memory for variable expansion"); + exit(EXIT_FAILURE); + } /* Build the new string. */ - if (segment_start) - strncat(new_str, string, segment_start); + if ((size_t)segment_end < strlen(string)) { + post_string = string + segment_end; + } + if (segment_start) { + pre_string = string; + pre_string[segment_start] = '\0'; + } + if (pre_string) + strlcat(new_str, pre_string, new_str_len); if (var_val != NULL) - strncat(new_str, var_val, var_val_len); - if (strlen(string) > (size_t)segment_end) - strcat(new_str, string + segment_end); - - pcre_free_substring(var_name); - if (default_val != NULL) - pcre_free_substring(default_val); + strlcat(new_str, var_val, new_str_len); + if (post_string != NULL) + strlcat(new_str, post_string, new_str_len); /* Recurse to expand other variables. */ char *new_new_str = ConfExpandEnvVar(new_str); @@ -884,6 +903,9 @@ ConfExpandEnvVar(char *string) new_str = new_new_str; } +end: + SCFree(string); + return new_str; }