aboutsummaryrefslogtreecommitdiff
path: root/src/bind_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bind_config.c')
-rw-r--r--src/bind_config.c147
1 files changed, 113 insertions, 34 deletions
diff --git a/src/bind_config.c b/src/bind_config.c
index ace5a0ac..a4c7a8d7 100644
--- a/src/bind_config.c
+++ b/src/bind_config.c
@@ -189,18 +189,29 @@ ssh_bind_config_parse_line(ssh_bind bind,
const char *line,
unsigned int count,
uint32_t *parser_flags,
- uint8_t *seen);
-
-static void local_parse_file(ssh_bind bind,
- const char *filename,
- uint32_t *parser_flags,
- uint8_t *seen)
+ uint8_t *seen,
+ unsigned int depth);
+
+#define LIBSSH_BIND_CONF_MAX_DEPTH 16
+static void
+local_parse_file(ssh_bind bind,
+ const char *filename,
+ uint32_t *parser_flags,
+ uint8_t *seen,
+ unsigned int depth)
{
FILE *f;
char line[MAX_LINE_SIZE] = {0};
unsigned int count = 0;
int rv;
+ if (depth > LIBSSH_BIND_CONF_MAX_DEPTH) {
+ ssh_set_error(bind, SSH_FATAL,
+ "ERROR - Too many levels of configuration includes "
+ "when processing file '%s'", filename);
+ return;
+ }
+
f = fopen(filename, "r");
if (f == NULL) {
SSH_LOG(SSH_LOG_RARE, "Cannot find file %s to load",
@@ -213,7 +224,7 @@ static void local_parse_file(ssh_bind bind,
while (fgets(line, sizeof(line), f)) {
count++;
- rv = ssh_bind_config_parse_line(bind, line, count, parser_flags, seen);
+ rv = ssh_bind_config_parse_line(bind, line, count, parser_flags, seen, depth);
if (rv < 0) {
fclose(f);
return;
@@ -228,7 +239,8 @@ static void local_parse_file(ssh_bind bind,
static void local_parse_glob(ssh_bind bind,
const char *fileglob,
uint32_t *parser_flags,
- uint8_t *seen)
+ uint8_t *seen,
+ unsigned int depth)
{
glob_t globbuf = {
.gl_flags = 0,
@@ -248,7 +260,7 @@ static void local_parse_glob(ssh_bind bind,
}
for (i = 0; i < globbuf.gl_pathc; i++) {
- local_parse_file(bind, globbuf.gl_pathv[i], parser_flags, seen);
+ local_parse_file(bind, globbuf.gl_pathv[i], parser_flags, seen, depth);
}
globfree(&globbuf);
@@ -274,7 +286,8 @@ ssh_bind_config_parse_line(ssh_bind bind,
const char *line,
unsigned int count,
uint32_t *parser_flags,
- uint8_t *seen)
+ uint8_t *seen,
+ unsigned int depth)
{
enum ssh_bind_config_opcode_e opcode;
const char *p = NULL;
@@ -288,7 +301,12 @@ ssh_bind_config_parse_line(ssh_bind bind,
return -1;
}
- if ((line == NULL) || (parser_flags == NULL)) {
+ /* Ignore empty lines */
+ if (line == NULL || *line == '\0') {
+ return 0;
+ }
+
+ if (parser_flags == NULL) {
ssh_set_error_invalid(bind);
return -1;
}
@@ -333,9 +351,9 @@ ssh_bind_config_parse_line(ssh_bind bind,
p = ssh_config_get_str_tok(&s, NULL);
if (p && (*parser_flags & PARSING)) {
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
- local_parse_glob(bind, p, parser_flags, seen);
+ local_parse_glob(bind, p, parser_flags, seen, depth + 1);
#else
- local_parse_file(bind, p, parser_flags, seen);
+ local_parse_file(bind, p, parser_flags, seen, depth + 1);
#endif /* HAVE_GLOB */
}
break;
@@ -345,7 +363,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
if (p && (*parser_flags & PARSING)) {
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set Hostkey value '%s'",
count, p);
}
@@ -356,7 +374,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
if (p && (*parser_flags & PARSING)) {
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDADDR, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set ListenAddress value '%s'",
count, p);
}
@@ -367,7 +385,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
if (p && (*parser_flags & PARSING)) {
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_BINDPORT_STR, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set Port value '%s'",
count, p);
}
@@ -378,7 +396,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
if (p && (*parser_flags & PARSING)) {
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_C_S, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set C->S Ciphers value '%s'",
count, p);
break;
@@ -386,7 +404,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_CIPHERS_S_C, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set S->C Ciphers value '%s'",
count, p);
}
@@ -397,7 +415,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
if (p && (*parser_flags & PARSING)) {
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_C_S, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set C->S MAC value '%s'",
count, p);
break;
@@ -405,7 +423,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HMAC_S_C, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set S->C MAC value '%s'",
count, p);
}
@@ -419,10 +437,10 @@ ssh_bind_config_parse_line(ssh_bind bind,
if (strcasecmp(p, "quiet") == 0) {
value = SSH_LOG_NONE;
} else if (strcasecmp(p, "fatal") == 0 ||
- strcasecmp(p, "error")== 0 ||
- strcasecmp(p, "info") == 0) {
+ strcasecmp(p, "error")== 0) {
value = SSH_LOG_WARN;
- } else if (strcasecmp(p, "verbose") == 0) {
+ } else if (strcasecmp(p, "verbose") == 0 ||
+ strcasecmp(p, "info") == 0) {
value = SSH_LOG_INFO;
} else if (strcasecmp(p, "DEBUG") == 0 ||
strcasecmp(p, "DEBUG1") == 0) {
@@ -435,7 +453,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_LOG_VERBOSITY,
&value);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set LogLevel value '%s'",
count, p);
}
@@ -447,7 +465,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
if (p && (*parser_flags & PARSING)) {
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_KEY_EXCHANGE, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set KexAlgorithms value '%s'",
count, p);
}
@@ -522,13 +540,13 @@ ssh_bind_config_parse_line(ssh_bind bind,
/* Skip one argument */
p = ssh_config_get_str_tok(&s, NULL);
if (p == NULL || p[0] == '\0') {
- SSH_LOG(SSH_LOG_WARN, "line %d: Match keyword "
+ SSH_LOG(SSH_LOG_TRACE, "line %d: Match keyword "
"'%s' requires argument\n", count, p2);
SAFE_FREE(x);
return -1;
}
args++;
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_DEBUG,
"line %d: Unsupported Match keyword '%s', ignoring\n",
count,
p2);
@@ -558,7 +576,7 @@ ssh_bind_config_parse_line(ssh_bind bind,
rc = ssh_bind_options_set(bind,
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set PubKeyAcceptedKeyTypes value '%s'",
count, p);
}
@@ -570,26 +588,26 @@ ssh_bind_config_parse_line(ssh_bind bind,
rc = ssh_bind_options_set(bind,
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS, p);
if (rc != 0) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"line %d: Failed to set HostkeyAlgorithms value '%s'",
count, p);
}
}
break;
case BIND_CFG_NOT_ALLOWED_IN_MATCH:
- SSH_LOG(SSH_LOG_WARN, "Option not allowed in Match block: %s, line: %d",
+ SSH_LOG(SSH_LOG_DEBUG, "Option not allowed in Match block: %s, line: %d",
keyword, count);
break;
case BIND_CFG_UNKNOWN:
- SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d",
+ SSH_LOG(SSH_LOG_TRACE, "Unknown option: %s, line: %d",
keyword, count);
break;
case BIND_CFG_UNSUPPORTED:
- SSH_LOG(SSH_LOG_WARN, "Unsupported option: %s, line: %d",
+ SSH_LOG(SSH_LOG_TRACE, "Unsupported option: %s, line: %d",
keyword, count);
break;
case BIND_CFG_NA:
- SSH_LOG(SSH_LOG_WARN, "Option not applicable: %s, line: %d",
+ SSH_LOG(SSH_LOG_TRACE, "Option not applicable: %s, line: %d",
keyword, count);
break;
default:
@@ -628,7 +646,7 @@ int ssh_bind_config_parse_file(ssh_bind bind, const char *filename)
parser_flags = PARSING;
while (fgets(line, sizeof(line), f)) {
count++;
- rv = ssh_bind_config_parse_line(bind, line, count, &parser_flags, seen);
+ rv = ssh_bind_config_parse_line(bind, line, count, &parser_flags, seen, 0);
if (rv) {
fclose(f);
return -1;
@@ -638,3 +656,64 @@ int ssh_bind_config_parse_file(ssh_bind bind, const char *filename)
fclose(f);
return 0;
}
+
+/* @brief Parse configuration string and set the options to the given bind session
+ *
+ * @params[in] bind The ssh bind session
+ * @params[in] input Null terminated string containing the configuration
+ *
+ * @returns SSH_OK on successful parsing the configuration string,
+ * SSH_ERROR on error
+ */
+int ssh_bind_config_parse_string(ssh_bind bind, const char *input)
+{
+ char line[MAX_LINE_SIZE] = {0};
+ const char *c = input, *line_start = input;
+ unsigned int line_num = 0, line_len;
+ uint32_t parser_flags;
+ int rv;
+
+ /* This local table is used during the parsing of the current file (and
+ * files included recursively in this file) to prevent an option to be
+ * redefined, i.e. the first value set is kept. But this DO NOT prevent the
+ * option to be redefined later by another file. */
+ uint8_t seen[BIND_CFG_MAX] = {0};
+
+ SSH_LOG(SSH_LOG_DEBUG, "Reading bind configuration data from string:");
+ SSH_LOG(SSH_LOG_DEBUG, "START\n%s\nEND", input);
+
+ parser_flags = PARSING;
+ while (1) {
+ line_num++;
+ line_start = c;
+ c = strchr(line_start, '\n');
+ if (c == NULL) {
+ /* if there is no newline at the end of the string */
+ c = strchr(line_start, '\0');
+ }
+ if (c == NULL) {
+ /* should not happen, would mean a string without trailing '\0' */
+ SSH_LOG(SSH_LOG_WARN, "No trailing '\\0' in config string");
+ return SSH_ERROR;
+ }
+ line_len = c - line_start;
+ if (line_len > MAX_LINE_SIZE - 1) {
+ SSH_LOG(SSH_LOG_WARN, "Line %u too long: %u characters",
+ line_num, line_len);
+ return SSH_ERROR;
+ }
+ memcpy(line, line_start, line_len);
+ line[line_len] = '\0';
+ SSH_LOG(SSH_LOG_DEBUG, "Line %u: %s", line_num, line);
+ rv = ssh_bind_config_parse_line(bind, line, line_num, &parser_flags, seen, 0);
+ if (rv < 0) {
+ return SSH_ERROR;
+ }
+ if (*c == '\0') {
+ break;
+ }
+ c++;
+ }
+
+ return SSH_OK;
+}