mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-03-24 20:40:09 +09:00
tests: Add tests for originalhost/host separation and Match support
Signed-off-by: Rui Li <ruili3422@gmail.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
@@ -130,23 +130,23 @@ extern LIBSSH_THREAD int ssh_log_level;
|
||||
"ProxyJump = many-spaces.com\n" /* valid */
|
||||
|
||||
/* Match keyword */
|
||||
#define LIBSSH_TESTCONFIG_STRING10 \
|
||||
"Match host example\n" \
|
||||
"\tHostName example.com\n" \
|
||||
"Match host example1,example2\n" \
|
||||
"\tHostName exampleN\n" \
|
||||
"Match user guest\n" \
|
||||
"\tHostName guest.com\n" \
|
||||
"Match user tester host testhost\n" \
|
||||
"\tHostName testhost.com\n" \
|
||||
#define LIBSSH_TESTCONFIG_STRING10 \
|
||||
"Match host example\n" \
|
||||
"\tHostName example.com\n" \
|
||||
"Match host example1,example2\n" \
|
||||
"\tHostName exampleN\n" \
|
||||
"Match user guest\n" \
|
||||
"\tHostName guest.com\n" \
|
||||
"Match user tester host testhost\n" \
|
||||
"\tHostName testhost.com\n" \
|
||||
"Match !user tester host testhost\n" \
|
||||
"\tHostName nonuser-testhost.com\n" \
|
||||
"Match all\n" \
|
||||
"\tHostName all-matched.com\n" \
|
||||
/* Unsupported options */ \
|
||||
"Match originalhost example\n" \
|
||||
"\tHostName original-example.com\n" \
|
||||
"Match localuser guest\n" \
|
||||
"\tHostName nonuser-testhost.com\n" \
|
||||
"Match all\n" \
|
||||
"\tHostName all-matched.com\n" \
|
||||
"Match originalhost example\n" \
|
||||
"\tHostName original-example.com\n" \
|
||||
"\tUser originaluser\n" \
|
||||
"Match localuser guest\n" \
|
||||
"\tHostName local-guest.com\n"
|
||||
|
||||
/* ProxyJump */
|
||||
@@ -851,26 +851,40 @@ static void torture_config_match(void **state,
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "unmatched");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "all-matched.com");
|
||||
assert_string_equal(session->opts.originalhost, "unmatched");
|
||||
|
||||
/* Hostname example does simple hostname matching */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "example");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "example.com");
|
||||
assert_string_equal(session->opts.originalhost, "example");
|
||||
|
||||
/* We can match also both hosts from a comma separated list */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "example1");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "exampleN");
|
||||
assert_string_equal(session->opts.originalhost, "example1");
|
||||
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "example2");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "exampleN");
|
||||
assert_string_equal(session->opts.originalhost, "example2");
|
||||
|
||||
/* We can match by user */
|
||||
/* We can match by originalhost */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "example");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "example.com");
|
||||
assert_string_equal(session->opts.originalhost, "example");
|
||||
/* Match originalhost sets User */
|
||||
assert_string_equal(session->opts.username, "originaluser");
|
||||
|
||||
/* We can match by user - clear originalhost to isolate user match */
|
||||
torture_reset_config(session);
|
||||
SAFE_FREE(session->opts.originalhost);
|
||||
ssh_options_set(session, SSH_OPTIONS_USER, "guest");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "guest.com");
|
||||
@@ -881,6 +895,7 @@ static void torture_config_match(void **state,
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "testhost.com");
|
||||
assert_string_equal(session->opts.originalhost, "testhost");
|
||||
|
||||
/* We can also negate conditions */
|
||||
torture_reset_config(session);
|
||||
@@ -888,9 +903,43 @@ static void torture_config_match(void **state,
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "nonuser-testhost.com");
|
||||
assert_string_equal(session->opts.originalhost, "testhost");
|
||||
|
||||
/* In this part, we try various other config files and strings. */
|
||||
|
||||
/* Match host compares against resolved hostname */
|
||||
config = "Host ssh-host\n"
|
||||
"\tHostname 10.1.1.1\n"
|
||||
"Match host 10.1.1.*\n"
|
||||
"\tPort 2222\n";
|
||||
if (file != NULL) {
|
||||
torture_write_file(file, config);
|
||||
} else {
|
||||
string = config;
|
||||
}
|
||||
torture_reset_config(session);
|
||||
session->opts.port = 0;
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "ssh-host");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "10.1.1.1");
|
||||
assert_string_equal(session->opts.originalhost, "ssh-host");
|
||||
assert_int_equal(session->opts.port, 2222);
|
||||
|
||||
/* Match host falls back to originalhost when host is NULL */
|
||||
config = "Match host my_alias\n"
|
||||
"\tHostName alias-matched.com\n";
|
||||
if (file != NULL) {
|
||||
torture_write_file(file, config);
|
||||
} else {
|
||||
string = config;
|
||||
}
|
||||
torture_reset_config(session);
|
||||
SAFE_FREE(session->opts.username);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "my_alias");
|
||||
assert_null(session->opts.host);
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "alias-matched.com");
|
||||
|
||||
/* Match final is not completely supported, but should do quite much the
|
||||
* same as "match all". The trailing "all" is not mandatory. */
|
||||
config = "Match final all\n"
|
||||
@@ -1018,7 +1067,7 @@ static void torture_config_match(void **state,
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.host, "unmatched");
|
||||
|
||||
/* Missing argument to unsupported option originalhost */
|
||||
/* Missing argument to option originalhost */
|
||||
config = "Match originalhost\n"
|
||||
"\tHost originalhost.com\n";
|
||||
if (file != NULL) {
|
||||
@@ -1289,7 +1338,6 @@ static void torture_config_proxyjump(void **state,
|
||||
assert_string_equal(session->opts.ProxyCommand,
|
||||
"ssh -W '[%h]:%p' 2620:52:0::fed");
|
||||
|
||||
|
||||
/* Multiple @ is allowed in second jump */
|
||||
config = "Host allowed-hostname\n"
|
||||
"\tProxyJump localhost,user@principal.com@jumpbox:22\n";
|
||||
@@ -1351,7 +1399,73 @@ static void torture_config_proxyjump(void **state,
|
||||
"jumpbox",
|
||||
"user@principal.com",
|
||||
"22");
|
||||
/* Non-RFC-1035 alias (underscore) — accepted with non-strict parse */
|
||||
config = "Host alias-jump\n"
|
||||
"\tProxyJump my_alias\n";
|
||||
if (file != NULL) {
|
||||
torture_write_file(file, config);
|
||||
} else {
|
||||
string = config;
|
||||
}
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "alias-jump");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root,
|
||||
"my_alias",
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Non-RFC-1035 alias in multi-hop second jump */
|
||||
config = "Host alias-multi\n"
|
||||
"\tProxyJump localhost,my_alias:2222\n";
|
||||
if (file != NULL) {
|
||||
torture_write_file(file, config);
|
||||
} else {
|
||||
string = config;
|
||||
}
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "alias-multi");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root,
|
||||
"my_alias",
|
||||
NULL,
|
||||
"2222");
|
||||
helper_proxy_jump_check(session->opts.proxy_jumps->root->next,
|
||||
"localhost",
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
/* Non-RFC-1035 alias — proxycommand based */
|
||||
torture_setenv("OPENSSH_PROXYJUMP", "1");
|
||||
|
||||
config = "Host alias-jump\n"
|
||||
"\tProxyJump my_alias\n";
|
||||
if (file != NULL) {
|
||||
torture_write_file(file, config);
|
||||
} else {
|
||||
string = config;
|
||||
}
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "alias-jump");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.ProxyCommand,
|
||||
"ssh -W '[%h]:%p' my_alias");
|
||||
|
||||
/* Non-RFC-1035 alias in multi-hop — proxycommand based */
|
||||
config = "Host alias-multi\n"
|
||||
"\tProxyJump localhost,my_alias:2222\n";
|
||||
if (file != NULL) {
|
||||
torture_write_file(file, config);
|
||||
} else {
|
||||
string = config;
|
||||
}
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "alias-multi");
|
||||
_parse_config(session, file, string, SSH_OK);
|
||||
assert_string_equal(session->opts.ProxyCommand,
|
||||
"ssh -J my_alias:2222 -W '[%h]:%p' localhost");
|
||||
|
||||
torture_unsetenv("OPENSSH_PROXYJUMP");
|
||||
|
||||
/* In this part, we try various other config files and strings. */
|
||||
torture_setenv("OPENSSH_PROXYJUMP", "1");
|
||||
@@ -2762,21 +2876,36 @@ static void torture_config_parse_uri(void **state)
|
||||
|
||||
(void)state; /* unused */
|
||||
|
||||
rc = ssh_config_parse_uri("localhost", &username, &hostname, &port, false, true);
|
||||
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, true);
|
||||
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, true);
|
||||
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 +2913,12 @@ 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, true);
|
||||
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,7 +2927,12 @@ 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, 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");
|
||||
@@ -2803,13 +2942,23 @@ static void torture_config_parse_uri(void **state)
|
||||
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);
|
||||
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);
|
||||
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");
|
||||
@@ -2817,11 +2966,21 @@ static void torture_config_parse_uri(void **state)
|
||||
SAFE_FREE(hostname);
|
||||
|
||||
/* Strict rejects what non-strict accepts */
|
||||
rc = ssh_config_parse_uri("customer_1", &username, &hostname, NULL, true, true);
|
||||
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);
|
||||
rc = ssh_config_parse_uri("host;cmd",
|
||||
&username,
|
||||
&hostname,
|
||||
NULL,
|
||||
true,
|
||||
false);
|
||||
assert_int_equal(rc, SSH_ERROR);
|
||||
|
||||
/* Non-strict rejects leading dash */
|
||||
@@ -2959,6 +3118,48 @@ static void torture_config_jump(void **state)
|
||||
printf("%s: EOF\n", __func__);
|
||||
}
|
||||
|
||||
/* Verify Hostname directive resolves host without overwriting originalhost
|
||||
*/
|
||||
static void torture_config_hostname(void **state)
|
||||
{
|
||||
ssh_session session = *state;
|
||||
char *expanded = NULL;
|
||||
|
||||
/* Hostname directive sets host, originalhost is unchanged */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "my_alias");
|
||||
assert_null(session->opts.host);
|
||||
assert_string_equal(session->opts.originalhost, "my_alias");
|
||||
_parse_config(session,
|
||||
NULL,
|
||||
"Host my_alias\n\tHostname 192.168.1.1\n",
|
||||
SSH_OK);
|
||||
assert_string_equal(session->opts.host, "192.168.1.1");
|
||||
assert_string_equal(session->opts.originalhost, "my_alias");
|
||||
|
||||
/* Host keyword compares against originalhost, not the resolved IP */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "ssh-host");
|
||||
_parse_config(session,
|
||||
NULL,
|
||||
"Host ssh-host\n\tHostname 10.1.1.1\n"
|
||||
"Host 10.1.1.*\n\tProxyJump ssh-host\n",
|
||||
SSH_OK);
|
||||
assert_string_equal(session->opts.host, "10.1.1.1");
|
||||
assert_string_equal(session->opts.originalhost, "ssh-host");
|
||||
assert_int_equal(ssh_list_count(session->opts.proxy_jumps), 0);
|
||||
assert_null(session->opts.ProxyCommand);
|
||||
|
||||
/* %h falls back to originalhost when host is not yet resolved */
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "my_alias");
|
||||
assert_null(session->opts.host);
|
||||
expanded = ssh_path_expand_escape(session, "%h");
|
||||
assert_non_null(expanded);
|
||||
assert_string_equal(expanded, "my_alias");
|
||||
free(expanded);
|
||||
}
|
||||
|
||||
/* Invalid configuration files
|
||||
*/
|
||||
static void torture_config_invalid(void **state)
|
||||
@@ -3127,7 +3328,8 @@ int torture_run_tests(void)
|
||||
cmocka_unit_test_setup_teardown(torture_config_loglevel_missing_value,
|
||||
setup,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_config_jump,
|
||||
cmocka_unit_test_setup_teardown(torture_config_jump, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_config_hostname,
|
||||
setup,
|
||||
teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_config_invalid,
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
#include <libssh/pki.h>
|
||||
#include <libssh/pki_priv.h>
|
||||
#include <libssh/session.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <netioapi.h>
|
||||
#else
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
#include <libssh/bind.h>
|
||||
#define LIBSSH_CUSTOM_BIND_CONFIG_FILE "my_bind_config"
|
||||
@@ -59,12 +66,16 @@ static void torture_options_set_host(void **state) {
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host, "localhost");
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "localhost");
|
||||
|
||||
/* IPv4 address */
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "127.1.1.1");
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host, "127.1.1.1");
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "127.1.1.1");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
/* IPv6 address */
|
||||
@@ -72,12 +83,16 @@ static void torture_options_set_host(void **state) {
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host, "::1");
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "::1");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "guru@meditation");
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host, "meditation");
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "meditation");
|
||||
assert_non_null(session->opts.username);
|
||||
assert_string_equal(session->opts.username, "guru");
|
||||
|
||||
@@ -86,6 +101,8 @@ static void torture_options_set_host(void **state) {
|
||||
assert_true(rc == 0);
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host, "hostname");
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "hostname");
|
||||
assert_non_null(session->opts.username);
|
||||
assert_string_equal(session->opts.username, "at@login");
|
||||
|
||||
@@ -104,6 +121,9 @@ static void torture_options_set_host(void **state) {
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host,
|
||||
"fd4d:5449:7400:111:626d:3cff:fedf:4d39");
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost,
|
||||
"fd4d:5449:7400:111:626d:3cff:fedf:4d39");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
/* IPv6 hostnames should work also with square braces */
|
||||
@@ -114,20 +134,103 @@ static void torture_options_set_host(void **state) {
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host,
|
||||
"fd4d:5449:7400:111:626d:3cff:fedf:4d39");
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost,
|
||||
"fd4d:5449:7400:111:626d:3cff:fedf:4d39");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
/* user@IPv6%interface
|
||||
* Use dynamic interface name for cross-platform portability */
|
||||
{
|
||||
char interf[IF_NAMESIZE] = {0};
|
||||
char ipv6_zone[128] = {0};
|
||||
char expected_host[128] = {0};
|
||||
|
||||
if_indextoname(1, interf);
|
||||
assert_non_null(interf);
|
||||
snprintf(ipv6_zone, sizeof(ipv6_zone), "user@fe80::1%%%s", interf);
|
||||
snprintf(expected_host, sizeof(expected_host), "fe80::1%%%s", interf);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, ipv6_zone);
|
||||
assert_return_code(rc, errno);
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host, expected_host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, expected_host);
|
||||
assert_string_equal(session->opts.username, "user");
|
||||
}
|
||||
|
||||
/* IDN need to be in punycode format */
|
||||
SAFE_FREE(session->opts.username);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "xn--bcher-kva.tld");
|
||||
assert_return_code(rc, errno);
|
||||
assert_non_null(session->opts.host);
|
||||
assert_string_equal(session->opts.host, "xn--bcher-kva.tld");
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "xn--bcher-kva.tld");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
/* IDN in UTF8 won't work */
|
||||
/* IDN in UTF-8 is accepted but not as a valid hostname,
|
||||
* only originalhost is set */
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "bücher.tld");
|
||||
assert_string_equal(ssh_get_error(session),
|
||||
"Invalid argument in ssh_options_set");
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "bücher.tld");
|
||||
|
||||
/* Config alias '%' rejected by RFC1035, only originalhost is set */
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "%customer1");
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "%customer1");
|
||||
|
||||
/* user@alias '_' rejected by RFC1035, alias stored in originalhost */
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "admin@customer_1");
|
||||
assert_return_code(rc, errno);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "customer_1");
|
||||
assert_string_equal(session->opts.username, "admin");
|
||||
|
||||
/* Shell metacharacters and leading dash rejected.
|
||||
* Verify failure cases do not update session options. */
|
||||
SAFE_FREE(session->opts.username);
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "host;rm -rf /");
|
||||
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "customer_1");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "-leading-dash");
|
||||
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "customer_1");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
/* Empty user or host rejected */
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "@hostname");
|
||||
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "customer_1");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "user@");
|
||||
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "customer_1");
|
||||
assert_null(session->opts.username);
|
||||
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "");
|
||||
assert_ssh_return_code_equal(session, rc, SSH_ERROR);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
assert_string_equal(session->opts.originalhost, "customer_1");
|
||||
assert_null(session->opts.username);
|
||||
}
|
||||
|
||||
static void torture_options_set_ciphers(void **state)
|
||||
@@ -714,6 +817,26 @@ static void torture_options_get_host(void **state)
|
||||
|
||||
assert_string_equal(host, "localhost");
|
||||
ssh_string_free_char(host);
|
||||
|
||||
/* When host is not yet resolved, falls back to originalhost */
|
||||
rc = ssh_options_set(session, SSH_OPTIONS_HOST, "my_alias");
|
||||
assert_true(rc == 0);
|
||||
assert_null(session->opts.host);
|
||||
assert_non_null(session->opts.originalhost);
|
||||
|
||||
assert_false(ssh_options_get(session, SSH_OPTIONS_HOST, &host));
|
||||
assert_string_equal(host, "my_alias");
|
||||
ssh_string_free_char(host);
|
||||
|
||||
/* After config resolution, get returns resolved host, not originalhost */
|
||||
session->opts.host = strdup("192.168.1.1");
|
||||
assert_non_null(session->opts.host);
|
||||
|
||||
assert_false(ssh_options_get(session, SSH_OPTIONS_HOST, &host));
|
||||
assert_string_equal(host, "192.168.1.1");
|
||||
ssh_string_free_char(host);
|
||||
/* originalhost is unchanged */
|
||||
assert_string_equal(session->opts.originalhost, "my_alias");
|
||||
}
|
||||
|
||||
static void torture_options_set_port(void **state)
|
||||
@@ -1074,6 +1197,7 @@ static void torture_options_config_host(void **state)
|
||||
{
|
||||
ssh_session session = *state;
|
||||
FILE *config = NULL;
|
||||
int rv;
|
||||
|
||||
/* create a new config file */
|
||||
config = fopen("test_config", "w");
|
||||
@@ -1113,6 +1237,33 @@ static void torture_options_config_host(void **state)
|
||||
ssh_options_parse_config(session, "test_config");
|
||||
assert_int_equal(session->opts.port, 44);
|
||||
|
||||
/* ssh_options_parse_config rejects when originalhost is NULL */
|
||||
SAFE_FREE(session->opts.host);
|
||||
SAFE_FREE(session->opts.originalhost);
|
||||
rv = ssh_options_parse_config(session, "test_config");
|
||||
assert_int_equal(rv, -1);
|
||||
|
||||
/* Config Hostname with invalid hostname: verify stale host not leaked */
|
||||
torture_write_file("test_config", "Host 192.168.1.1\nHostname my_alias\n");
|
||||
|
||||
torture_reset_config(session);
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "192.168.1.1");
|
||||
assert_string_equal(session->opts.host, "192.168.1.1");
|
||||
assert_string_equal(session->opts.originalhost, "192.168.1.1");
|
||||
rv = ssh_options_parse_config(session, "test_config");
|
||||
assert_int_equal(rv, 0);
|
||||
assert_null(session->opts.host);
|
||||
assert_string_equal(session->opts.originalhost, "192.168.1.1");
|
||||
|
||||
/* Calling ssh_options_set(HOST) twice: verify stale host not leaked */
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "real.server.com");
|
||||
assert_string_equal(session->opts.host, "real.server.com");
|
||||
assert_string_equal(session->opts.originalhost, "real.server.com");
|
||||
|
||||
ssh_options_set(session, SSH_OPTIONS_HOST, "my_alias");
|
||||
assert_null(session->opts.host);
|
||||
assert_string_equal(session->opts.originalhost, "my_alias");
|
||||
|
||||
unlink("test_config");
|
||||
}
|
||||
|
||||
@@ -1437,6 +1588,7 @@ static void torture_options_copy(void **state)
|
||||
|
||||
assert_string_equal(session->opts.username, new->opts.username);
|
||||
assert_string_equal(session->opts.host, new->opts.host);
|
||||
assert_string_equal(session->opts.originalhost, new->opts.originalhost);
|
||||
assert_string_equal(session->opts.bindaddr, new->opts.bindaddr);
|
||||
assert_string_equal(session->opts.sshdir, new->opts.sshdir);
|
||||
assert_string_equal(session->opts.knownhosts, new->opts.knownhosts);
|
||||
|
||||
Reference in New Issue
Block a user