aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelen <jjelen@redhat.com>2018-09-04 13:46:37 +0200
committerAndreas Schneider <asn@cryptomilk.org>2018-09-05 11:43:05 +0200
commite9b44d26b12aa1314718a37fe2598dafb9843e3f (patch)
tree8f525fa749b4c5fcb52ed13043971434fd2cf547
parent9f5f10552b54d1e8a21f9ccbcf5bbe37744d36f6 (diff)
downloadlibssh-e9b44d26b12aa1314718a37fe2598dafb9843e3f.tar.gz
libssh-e9b44d26b12aa1314718a37fe2598dafb9843e3f.tar.xz
libssh-e9b44d26b12aa1314718a37fe2598dafb9843e3f.zip
config: Parse Match keyword
Amends f818e63f8, which introduced the constants and matching of this configuration option, but did not implement the handling of the values which was causing the configuration parser failing for certain configurations. This commit exposes match_pattern_list() from match.c Red Hat Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1624425 Signed-off-by: Jakub Jelen <jjelen@redhat.com> Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r--include/libssh/priv.h2
-rw-r--r--src/config.c165
-rw-r--r--src/match.c2
3 files changed, 167 insertions, 2 deletions
diff --git a/include/libssh/priv.h b/include/libssh/priv.h
index 2123fc03..31abb106 100644
--- a/include/libssh/priv.h
+++ b/include/libssh/priv.h
@@ -262,6 +262,8 @@ int compress_buffer(ssh_session session,ssh_buffer buf);
int decompress_buffer(ssh_session session,ssh_buffer buf, size_t maxlen);
/* match.c */
+int match_pattern_list(const char *string, const char *pattern,
+ unsigned int len, int dolower);
int match_hostname(const char *host, const char *pattern, unsigned int len);
/* connector.c */
diff --git a/src/config.c b/src/config.c
index 5d1baa51..3e94f6b8 100644
--- a/src/config.c
+++ b/src/config.c
@@ -30,6 +30,7 @@
#ifdef HAVE_GLOB_H
# include <glob.h>
#endif
+#include <stdbool.h>
#include "libssh/priv.h"
#include "libssh/session.h"
@@ -185,6 +186,32 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
{ NULL, SOC_UNKNOWN }
};
+enum ssh_config_match_e {
+ MATCH_UNKNOWN = -1,
+ MATCH_ALL,
+ MATCH_CANONICAL,
+ MATCH_EXEC,
+ MATCH_HOST,
+ MATCH_ORIGINALHOST,
+ MATCH_USER,
+ MATCH_LOCALUSER
+};
+
+struct ssh_config_match_keyword_table_s {
+ const char *name;
+ enum ssh_config_match_e opcode;
+};
+
+static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[] = {
+ { "all", MATCH_ALL },
+ { "canonical", MATCH_CANONICAL },
+ { "exec", MATCH_EXEC },
+ { "host", MATCH_HOST },
+ { "originalhost", MATCH_ORIGINALHOST },
+ { "user", MATCH_USER },
+ { "localuser", MATCH_LOCALUSER },
+};
+
static int ssh_config_parse_line(ssh_session session, const char *line,
unsigned int count, int *parsing, int seen[]);
@@ -351,6 +378,40 @@ static void local_parse_glob(ssh_session session,
}
#endif /* HAVE_GLOB */
+static enum ssh_config_match_e
+ssh_config_get_match_opcode(const char *keyword)
+{
+ size_t i;
+
+ for (i = 0; ssh_config_match_keyword_table[i].name != NULL; i++) {
+ if (strcasecmp(keyword, ssh_config_match_keyword_table[i].name) == 0) {
+ return ssh_config_match_keyword_table[i].opcode;
+ }
+ }
+
+ return MATCH_UNKNOWN;
+}
+
+static int
+ssh_config_match(char *value, const char *pattern, bool negate)
+{
+ int ok, result = 0;
+ char *lowervalue;
+
+ lowervalue = (value) ? ssh_lowercase(value) : NULL;
+ ok = match_pattern_list(lowervalue, pattern, strlen(pattern), 0);
+ if (ok <= 0 && negate == true) {
+ result = 1;
+ } else if (ok > 0 && negate == false) {
+ result = 1;
+ }
+ SSH_LOG(SSH_LOG_TRACE, "%s '%s' against pattern '%s'%s (ok=%d)",
+ result == 1 ? "Matched" : "Not matched", value, pattern,
+ negate == true ? " (negated)" : "", ok);
+ SAFE_FREE(lowervalue);
+ return result;
+}
+
static int ssh_config_parse_line(ssh_session session, const char *line,
unsigned int count, int *parsing, int seen[]) {
enum ssh_config_opcode_e opcode;
@@ -384,7 +445,10 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
}
opcode = ssh_config_get_opcode(keyword);
- if (*parsing == 1 && opcode != SOC_HOST && opcode != SOC_INCLUDE &&
+ if (*parsing == 1 &&
+ opcode != SOC_HOST &&
+ opcode != SOC_MATCH &&
+ opcode != SOC_INCLUDE &&
opcode > SOC_UNSUPPORTED) { /* Ignore all unknown types here */
if (seen[opcode] != 0) {
SAFE_FREE(x);
@@ -405,6 +469,105 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
#endif /* HAVE_GLOB */
}
break;
+
+ case SOC_MATCH: {
+ bool negate;
+ int result = 1, args = 0;
+ enum ssh_config_match_e opt;
+
+ *parsing = 0;
+ do {
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p == NULL || p[0] == '\0') {
+ break;
+ }
+ args++;
+ SSH_LOG(SSH_LOG_TRACE, "line %d: Processing Match keyword '%s'",
+ count, p);
+
+ /* If the option is prefixed with ! the result should be negated */
+ negate = false;
+ if (p[0] == '!') {
+ negate = true;
+ p++;
+ }
+
+ opt = ssh_config_get_match_opcode(p);
+ switch (opt) {
+ case MATCH_ALL:
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (args == 1 && (p == NULL || p[0] == '\0')) {
+ /* The first argument and end of line */
+ if (negate == true) {
+ result = 0;
+ }
+ break;
+ }
+
+ ssh_set_error(session, SSH_FATAL,
+ "line %d: ERROR - Match all can not be combined with "
+ "other Match attributes", count);
+ SAFE_FREE(x);
+ return -1;
+
+ case MATCH_EXEC:
+ case MATCH_ORIGINALHOST:
+ case MATCH_LOCALUSER:
+ /* Skip one argument */
+ p = ssh_config_get_str_tok(&s, NULL);
+ args++;
+ FALL_THROUGH;
+ case MATCH_CANONICAL:
+ SSH_LOG(SSH_LOG_WARN, "line: %d: Unsupported Match keyword "
+ "'%s', Ignoring\n", count, p);
+ result = 0;
+ break;
+
+ case MATCH_HOST:
+ /* Here we match only one argument */
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p == NULL || p[0] == '\0') {
+ ssh_set_error(session, SSH_FATAL,
+ "line %d: ERROR - Match host keyword "
+ "requires argument", count);
+ SAFE_FREE(x);
+ return -1;
+ }
+ result &= ssh_config_match(session->opts.host, p, negate);
+ args++;
+ break;
+
+ case MATCH_USER:
+ /* Here we match only one argument */
+ p = ssh_config_get_str_tok(&s, NULL);
+ if (p == NULL || p[0] == '\0') {
+ ssh_set_error(session, SSH_FATAL,
+ "line %d: ERROR - Match user keyword "
+ "requires argument", count);
+ SAFE_FREE(x);
+ return -1;
+ }
+ result &= ssh_config_match(session->opts.username, p, negate);
+ args++;
+ break;
+
+ case MATCH_UNKNOWN:
+ default:
+ ssh_set_error(session, SSH_FATAL,
+ "ERROR - Unknown argument '%s' for Match keyword", p);
+ SAFE_FREE(x);
+ return -1;
+ }
+ } while (p != NULL && p[0] != '\0');
+ if (args < 1) {
+ ssh_set_error(session, SSH_FATAL,
+ "ERROR - Match keyword requires an argument");
+ SAFE_FREE(x);
+ return -1;
+ }
+ *parsing = result;
+ break;
+ }
case SOC_HOST: {
int ok = 0, result = -1;
diff --git a/src/match.c b/src/match.c
index ab943413..06587b92 100644
--- a/src/match.c
+++ b/src/match.c
@@ -119,7 +119,7 @@ static int match_pattern(const char *s, const char *pattern) {
* Returns -1 if negation matches, 1 if there is a positive match, 0 if there is
* no match at all.
*/
-static int match_pattern_list(const char *string, const char *pattern,
+int match_pattern_list(const char *string, const char *pattern,
unsigned int len, int dolower) {
char sub[1024];
int negated;