mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-03-24 20:40:09 +09:00
Add strict validation mode to ssh_config_parse_uri in config_parser
Signed-off-by: Rui Li <ruili3422@gmail.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
@@ -54,6 +54,11 @@ int ssh_config_get_yesno(char **str, int notfound);
|
||||
* be stored or NULL if we do not care about the result.
|
||||
* @param[in] ignore_port Set to true if we should not attempt to parse
|
||||
* port number.
|
||||
* @param[in] strict Set to true to validate hostname against RFC1035
|
||||
* (for resolving to a real host).
|
||||
* Set to false to only reject shell metacharacters
|
||||
* (allowing config aliases with non-RFC1035 chars
|
||||
* like underscores, resolved later via Hostname).
|
||||
*
|
||||
* @returns SSH_OK if the provided string is in format of SSH URI,
|
||||
* SSH_ERROR on failure
|
||||
@@ -62,7 +67,8 @@ int ssh_config_parse_uri(const char *tok,
|
||||
char **username,
|
||||
char **hostname,
|
||||
char **port,
|
||||
bool ignore_port);
|
||||
bool ignore_port,
|
||||
bool strict);
|
||||
|
||||
/**
|
||||
* @brief: Parse the ProxyJump configuration line and if parsing,
|
||||
|
||||
@@ -544,6 +544,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
||||
&jump_host->username,
|
||||
&jump_host->hostname,
|
||||
&port,
|
||||
false,
|
||||
false);
|
||||
if (rv != SSH_OK) {
|
||||
ssh_set_error_invalid(session);
|
||||
@@ -566,7 +567,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
||||
}
|
||||
} else if (parse_entry) {
|
||||
/* We actually care only about the first item */
|
||||
rv = ssh_config_parse_uri(cp, &username, &hostname, &port, false);
|
||||
rv = ssh_config_parse_uri(cp, &username, &hostname, &port, false, false);
|
||||
if (rv != SSH_OK) {
|
||||
ssh_set_error_invalid(session);
|
||||
goto out;
|
||||
@@ -582,7 +583,7 @@ ssh_config_parse_proxy_jump(ssh_session session, const char *s, bool do_parsing)
|
||||
}
|
||||
} else {
|
||||
/* The rest is just sanity-checked to avoid failures later */
|
||||
rv = ssh_config_parse_uri(cp, NULL, NULL, NULL, false);
|
||||
rv = ssh_config_parse_uri(cp, NULL, NULL, NULL, false, false);
|
||||
if (rv != SSH_OK) {
|
||||
ssh_set_error_invalid(session);
|
||||
goto out;
|
||||
|
||||
@@ -172,7 +172,8 @@ int ssh_config_parse_uri(const char *tok,
|
||||
char **username,
|
||||
char **hostname,
|
||||
char **port,
|
||||
bool ignore_port)
|
||||
bool ignore_port,
|
||||
bool strict)
|
||||
{
|
||||
char *endp = NULL;
|
||||
long port_n;
|
||||
@@ -243,13 +244,31 @@ int ssh_config_parse_uri(const char *tok,
|
||||
if (*hostname == NULL) {
|
||||
goto error;
|
||||
}
|
||||
/* if not an ip, check syntax */
|
||||
rc = ssh_is_ipaddr(*hostname);
|
||||
if (rc == 0) {
|
||||
rc = ssh_check_hostname_syntax(*hostname);
|
||||
if (rc != SSH_OK) {
|
||||
if (strict) {
|
||||
/* if not an ip, check syntax */
|
||||
rc = ssh_is_ipaddr(*hostname);
|
||||
if (rc == 0) {
|
||||
rc = ssh_check_hostname_syntax(*hostname);
|
||||
if (rc != SSH_OK) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Reject shell metacharacters to allow config aliases with
|
||||
* non-RFC1035 chars (e.g. %, _). Modeled on OpenSSH's
|
||||
* valid_hostname() in ssh.c. */
|
||||
const char *c = NULL;
|
||||
if ((*hostname)[0] == '-') {
|
||||
goto error;
|
||||
}
|
||||
for (c = *hostname; *c != '\0'; c++) {
|
||||
char *is_meta = strchr("'`\"$\\;&<>|(){},", *c);
|
||||
int is_space = isspace((unsigned char)*c);
|
||||
int is_ctrl = iscntrl((unsigned char)*c);
|
||||
if (is_meta != NULL || is_space || is_ctrl) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Skip also the closing bracket */
|
||||
|
||||
@@ -718,7 +718,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
||||
return -1;
|
||||
} else {
|
||||
char *username = NULL, *hostname = NULL;
|
||||
rc = ssh_config_parse_uri(value, &username, &hostname, NULL, true);
|
||||
rc = ssh_config_parse_uri(value, &username, &hostname, NULL, true, true);
|
||||
if (rc != SSH_OK) {
|
||||
ssh_set_error_invalid(session);
|
||||
return -1;
|
||||
|
||||
@@ -2762,21 +2762,21 @@ static void torture_config_parse_uri(void **state)
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
rc = ssh_config_parse_uri("localhost", &username, &hostname, &port, false);
|
||||
rc = ssh_config_parse_uri("localhost", &username, &hostname, &port, false, true);
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(username);
|
||||
assert_string_equal(hostname, "localhost");
|
||||
SAFE_FREE(hostname);
|
||||
assert_null(port);
|
||||
|
||||
rc = ssh_config_parse_uri("1.2.3.4", &username, &hostname, &port, false);
|
||||
rc = ssh_config_parse_uri("1.2.3.4", &username, &hostname, &port, false, true);
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(username);
|
||||
assert_string_equal(hostname, "1.2.3.4");
|
||||
SAFE_FREE(hostname);
|
||||
assert_null(port);
|
||||
|
||||
rc = ssh_config_parse_uri("1.2.3.4:2222", &username, &hostname, &port, false);
|
||||
rc = ssh_config_parse_uri("1.2.3.4:2222", &username, &hostname, &port, false, true);
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(username);
|
||||
assert_string_equal(hostname, "1.2.3.4");
|
||||
@@ -2784,7 +2784,7 @@ static void torture_config_parse_uri(void **state)
|
||||
assert_string_equal(port, "2222");
|
||||
SAFE_FREE(port);
|
||||
|
||||
rc = ssh_config_parse_uri("[1:2:3::4]:2222", &username, &hostname, &port, false);
|
||||
rc = ssh_config_parse_uri("[1:2:3::4]:2222", &username, &hostname, &port, false, true);
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(username);
|
||||
assert_string_equal(hostname, "1:2:3::4");
|
||||
@@ -2793,13 +2793,39 @@ static void torture_config_parse_uri(void **state)
|
||||
SAFE_FREE(port);
|
||||
|
||||
/* do not want port */
|
||||
rc = ssh_config_parse_uri("1:2:3::4", &username, &hostname, NULL, true);
|
||||
rc = ssh_config_parse_uri("1:2:3::4", &username, &hostname, NULL, true, true);
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(username);
|
||||
assert_string_equal(hostname, "1:2:3::4");
|
||||
SAFE_FREE(hostname);
|
||||
|
||||
rc = ssh_config_parse_uri("user -name@", &username, NULL, NULL, true);
|
||||
rc = ssh_config_parse_uri("user -name@", &username, NULL, NULL, true, true);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
/* Non-strict accepts non-RFC1035 chars (e.g. _, %) */
|
||||
rc = ssh_config_parse_uri("customer_1", &username, &hostname, NULL, true, false);
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(username);
|
||||
assert_string_equal(hostname, "customer_1");
|
||||
SAFE_FREE(hostname);
|
||||
|
||||
rc = ssh_config_parse_uri("admin@%prod", &username, &hostname, NULL, true, false);
|
||||
assert_return_code(rc, errno);
|
||||
assert_string_equal(username, "admin");
|
||||
assert_string_equal(hostname, "%prod");
|
||||
SAFE_FREE(username);
|
||||
SAFE_FREE(hostname);
|
||||
|
||||
/* Strict rejects what non-strict accepts */
|
||||
rc = ssh_config_parse_uri("customer_1", &username, &hostname, NULL, true, true);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
/* Non-strict rejects shell metacharacters */
|
||||
rc = ssh_config_parse_uri("host;cmd", &username, &hostname, NULL, true, false);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
/* Non-strict rejects leading dash */
|
||||
rc = ssh_config_parse_uri("-host", &username, &hostname, NULL, true, false);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user