diff options
-rw-r--r-- | tests/unittests/torture_config.c | 1238 |
1 files changed, 815 insertions, 423 deletions
diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c index 671e88c2..7ae846a4 100644 --- a/tests/unittests/torture_config.c +++ b/tests/unittests/torture_config.c @@ -10,6 +10,18 @@ extern LIBSSH_THREAD int ssh_log_level; +#define USERNAME "testuser" +#define PROXYCMD "ssh -q -W %h:%p gateway.example.com" +#define ID_FILE "/etc/xxx" +#define KEXALGORITHMS "ecdh-sha2-nistp521,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha1" +#define HOSTKEYALGORITHMS "ssh-ed25519,ecdsa-sha2-nistp521,ssh-rsa" +#define PUBKEYACCEPTEDTYPES "rsa-sha2-512,ssh-rsa,ecdsa-sha2-nistp521" +#define MACS "hmac-sha1,hmac-sha2-256,hmac-sha2-512,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com" +#define USER_KNOWN_HOSTS "%d/my_known_hosts" +#define GLOBAL_KNOWN_HOSTS "/etc/ssh/my_ssh_known_hosts" +#define BIND_ADDRESS "::1" + + #define LIBSSH_TESTCONFIG1 "libssh_testconfig1.tmp" #define LIBSSH_TESTCONFIG2 "libssh_testconfig2.tmp" #define LIBSSH_TESTCONFIG3 "libssh_testconfig3.tmp" @@ -23,25 +35,177 @@ extern LIBSSH_THREAD int ssh_log_level; #define LIBSSH_TESTCONFIG11 "libssh_testconfig11.tmp" #define LIBSSH_TESTCONFIG12 "libssh_testconfig12.tmp" #define LIBSSH_TESTCONFIGGLOB "libssh_testc*[36].tmp" -#define LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES "libssh_test_PubkeyAcceptedKeyTypes.tmp" +#define LIBSSH_TEST_PUBKEYTYPES "libssh_test_PubkeyAcceptedKeyTypes.tmp" +#define LIBSSH_TEST_NONEWLINEEND "libssh_test_NoNewLineEnd.tmp" +#define LIBSSH_TEST_NONEWLINEONELINE "libssh_test_NoNewLineOneline.tmp" + +#define LIBSSH_TESTCONFIG_STRING1 \ + "User "USERNAME"\nInclude "LIBSSH_TESTCONFIG2"\n\n" + +#define LIBSSH_TESTCONFIG_STRING2 \ + "Include "LIBSSH_TESTCONFIG3"\n" \ + "ProxyCommand "PROXYCMD"\n\n" + +#define LIBSSH_TESTCONFIG_STRING3 \ + "\n\nIdentityFile "ID_FILE"\n" \ + "\n\nKexAlgorithms "KEXALGORITHMS"\n" \ + "\n\nHostKeyAlgorithms "HOSTKEYALGORITHMS"\n" \ + "\n\nPubkeyAcceptedTypes "PUBKEYACCEPTEDTYPES"\n" \ + "\n\nMACs "MACS"\n" + +/* Multiple Port settings -> parsing returns early. */ +#define LIBSSH_TESTCONFIG_STRING4 \ + "Port 123\nPort 456\n" + +/* Testing glob include */ +#define LIBSSH_TESTCONFIG_STRING5 \ + "User "USERNAME"\nInclude "LIBSSH_TESTCONFIGGLOB"\n\n" \ + +#define LIBSSH_TESTCONFIG_STRING6 \ + "ProxyCommand "PROXYCMD"\n\n" + +/* new options */ +#define LIBSSH_TESTCONFIG_STRING7 \ + "\tBindAddress "BIND_ADDRESS"\n" \ + "\tConnectTimeout 30\n" \ + "\tLogLevel DEBUG3\n" \ + "\tGlobalKnownHostsFile "GLOBAL_KNOWN_HOSTS"\n" \ + "\tCompression yes\n" \ + "\tStrictHostkeyChecking no\n" \ + "\tGSSAPIDelegateCredentials yes\n" \ + "\tGSSAPIServerIdentity example.com\n" \ + "\tGSSAPIClientIdentity home.sweet\n" \ + "\tUserKnownHostsFile "USER_KNOWN_HOSTS"\n" + +/* authentication methods */ +#define LIBSSH_TESTCONFIG_STRING8 \ + "Host gss\n" \ + "\tGSSAPIAuthentication yes\n" \ + "Host kbd\n" \ + "\tKbdInteractiveAuthentication yes\n" \ + "Host pass\n" \ + "\tPasswordAuthentication yes\n" \ + "Host pubkey\n" \ + "\tPubkeyAuthentication yes\n" \ + "Host nogss\n" \ + "\tGSSAPIAuthentication no\n" \ + "Host nokbd\n" \ + "\tKbdInteractiveAuthentication no\n" \ + "Host nopass\n" \ + "\tPasswordAuthentication no\n" \ + "Host nopubkey\n" \ + "\tPubkeyAuthentication no\n" + +/* unsupported options and corner cases */ +#define LIBSSH_TESTCONFIG_STRING9 \ + "\n" /* empty line */ \ + "# comment line\n" \ + " # comment line not starting with hash\n" \ + "UnknownConfigurationOption yes\n" \ + "GSSAPIKexAlgorithms yes\n" \ + "ControlMaster auto\n" /* SOC_NA */ \ + "VisualHostkey yes\n" /* SOC_UNSUPPORTED */ \ + "HostName =equal.sign\n" /* valid */ \ + "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" \ + "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 local-guest.com\n" + +/* ProxyJump */ +#define LIBSSH_TESTCONFIG_STRING11 \ + "Host simple\n" \ + "\tProxyJump jumpbox\n" \ + "Host user\n" \ + "\tProxyJump user@jumpbox\n" \ + "Host port\n" \ + "\tProxyJump jumpbox:2222\n" \ + "Host two-step\n" \ + "\tProxyJump u1@first:222,u2@second:33\n" \ + "Host none\n" \ + "\tProxyJump none\n" \ + "Host only-command\n" \ + "\tProxyCommand "PROXYCMD"\n" \ + "\tProxyJump jumpbox\n" \ + "Host only-jump\n" \ + "\tProxyJump jumpbox\n" \ + "\tProxyCommand "PROXYCMD"\n" \ + "Host ipv6\n" \ + "\tProxyJump [2620:52:0::fed]\n" + +/* RekeyLimit combinations */ +#define LIBSSH_TESTCONFIG_STRING12 \ + "Host default\n" \ + "\tRekeyLimit default none\n" \ + "Host data1\n" \ + "\tRekeyLimit 42G\n" \ + "Host data2\n" \ + "\tRekeyLimit 31M\n" \ + "Host data3\n" \ + "\tRekeyLimit 521K\n" \ + "Host time1\n" \ + "\tRekeyLimit default 3D\n" \ + "Host time2\n" \ + "\tRekeyLimit default 2h\n" \ + "Host time3\n" \ + "\tRekeyLimit default 160m\n" \ + "Host time4\n" \ + "\tRekeyLimit default 9600\n" + +#define LIBSSH_TEST_PUBKEYTYPES_STRING \ + "PubkeyAcceptedKeyTypes "PUBKEYACCEPTEDTYPES"\n" + +#define LIBSSH_TEST_NONEWLINEEND_STRING \ + "ConnectTimeout 30\n" \ + "LogLevel DEBUG3" + +#define LIBSSH_TEST_NONEWLINEONELINE_STRING \ + "ConnectTimeout 30" -#define USERNAME "testuser" -#define PROXYCMD "ssh -q -W %h:%p gateway.example.com" -#define ID_FILE "/etc/xxx" -#define KEXALGORITHMS "ecdh-sha2-nistp521,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha1" -#define HOSTKEYALGORITHMS "ssh-ed25519,ecdsa-sha2-nistp521,ssh-rsa" -#define PUBKEYACCEPTEDTYPES "rsa-sha2-512,ssh-rsa,ecdsa-sha2-nistp521" -#define MACS "hmac-sha1,hmac-sha2-256,hmac-sha2-512,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com" -#define USER_KNOWN_HOSTS "%d/my_known_hosts" -#define GLOBAL_KNOWN_HOSTS "/etc/ssh/my_ssh_known_hosts" -#define BIND_ADDRESS "::1" +/** + * @brief helper function loading configuration from either file or string + */ +static void _parse_config(ssh_session session, + const char *file, const char *string, int expected) +{ + int ret = -1; + /* make sure either config file or config string is given, + * not both */ + assert_int_not_equal(file == NULL, string == NULL); + if (file != NULL) { + ret = ssh_config_parse_file(session, file); + } else if (string != NULL) { + ret = ssh_config_parse_string(session, string); + } else { + /* should not happen */ + fail(); + } + + /* make sure parsing went as expected */ + assert_ssh_return_code_equal(session, ret, expected); +} static int setup_config_files(void **state) { - ssh_session session; - int verbosity; + (void) state; /* unused */ unlink(LIBSSH_TESTCONFIG1); unlink(LIBSSH_TESTCONFIG2); @@ -55,154 +219,68 @@ static int setup_config_files(void **state) unlink(LIBSSH_TESTCONFIG10); unlink(LIBSSH_TESTCONFIG11); unlink(LIBSSH_TESTCONFIG12); - unlink(LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES); + unlink(LIBSSH_TEST_PUBKEYTYPES); + unlink(LIBSSH_TEST_NONEWLINEEND); + unlink(LIBSSH_TEST_NONEWLINEONELINE); torture_write_file(LIBSSH_TESTCONFIG1, - "User "USERNAME"\nInclude "LIBSSH_TESTCONFIG2"\n\n"); + LIBSSH_TESTCONFIG_STRING1); torture_write_file(LIBSSH_TESTCONFIG2, - "Include "LIBSSH_TESTCONFIG3"\n" - "ProxyCommand "PROXYCMD"\n\n"); + LIBSSH_TESTCONFIG_STRING2); torture_write_file(LIBSSH_TESTCONFIG3, - "\n\nIdentityFile "ID_FILE"\n" - "\n\nKexAlgorithms "KEXALGORITHMS"\n" - "\n\nHostKeyAlgorithms "HOSTKEYALGORITHMS"\n" - "\n\nPubkeyAcceptedTypes "PUBKEYACCEPTEDTYPES"\n" - "\n\nMACs "MACS"\n"); + LIBSSH_TESTCONFIG_STRING3); /* Multiple Port settings -> parsing returns early. */ torture_write_file(LIBSSH_TESTCONFIG4, - "Port 123\nPort 456\n"); + LIBSSH_TESTCONFIG_STRING4); /* Testing glob include */ torture_write_file(LIBSSH_TESTCONFIG5, - "User "USERNAME"\nInclude "LIBSSH_TESTCONFIGGLOB"\n\n"); + LIBSSH_TESTCONFIG_STRING5); torture_write_file(LIBSSH_TESTCONFIG6, - "ProxyCommand "PROXYCMD"\n\n"); + LIBSSH_TESTCONFIG_STRING6); /* new options */ torture_write_file(LIBSSH_TESTCONFIG7, - "\tBindAddress "BIND_ADDRESS"\n" - "\tConnectTimeout 30\n" - "\tLogLevel DEBUG3\n" - "\tGlobalKnownHostsFile "GLOBAL_KNOWN_HOSTS"\n" - "\tCompression yes\n" - "\tStrictHostkeyChecking no\n" - "\tGSSAPIDelegateCredentials yes\n" - "\tGSSAPIServerIdentity example.com\n" - "\tGSSAPIClientIdentity home.sweet\n" - "\tUserKnownHostsFile "USER_KNOWN_HOSTS"\n"); + LIBSSH_TESTCONFIG_STRING7); /* authentication methods */ torture_write_file(LIBSSH_TESTCONFIG8, - "Host gss\n" - "\tGSSAPIAuthentication yes\n" - "Host kbd\n" - "\tKbdInteractiveAuthentication yes\n" - "Host pass\n" - "\tPasswordAuthentication yes\n" - "Host pubkey\n" - "\tPubkeyAuthentication yes\n" - "Host nogss\n" - "\tGSSAPIAuthentication no\n" - "Host nokbd\n" - "\tKbdInteractiveAuthentication no\n" - "Host nopass\n" - "\tPasswordAuthentication no\n" - "Host nopubkey\n" - "\tPubkeyAuthentication no\n"); + LIBSSH_TESTCONFIG_STRING8); /* unsupported options and corner cases */ torture_write_file(LIBSSH_TESTCONFIG9, - "\n" /* empty line */ - "# comment line\n" - " # comment line not starting with hash\n" - "UnknownConfigurationOption yes\n" - "GSSAPIKexAlgorithms yes\n" - "ControlMaster auto\n" /* SOC_NA */ - "VisualHostkey yes\n" /* SOC_UNSUPPORTED */ - "HostName =equal.sign\n" /* valid */ - "ProxyJump = many-spaces.com\n" /* valid */ - ""); + LIBSSH_TESTCONFIG_STRING9); /* Match keyword */ torture_write_file(LIBSSH_TESTCONFIG10, - "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 local-guest.com\n" - ""); + LIBSSH_TESTCONFIG_STRING10); /* ProxyJump */ torture_write_file(LIBSSH_TESTCONFIG11, - "Host simple\n" - "\tProxyJump jumpbox\n" - "Host user\n" - "\tProxyJump user@jumpbox\n" - "Host port\n" - "\tProxyJump jumpbox:2222\n" - "Host two-step\n" - "\tProxyJump u1@first:222,u2@second:33\n" - "Host none\n" - "\tProxyJump none\n" - "Host only-command\n" - "\tProxyCommand "PROXYCMD"\n" - "\tProxyJump jumpbox\n" - "Host only-jump\n" - "\tProxyJump jumpbox\n" - "\tProxyCommand "PROXYCMD"\n" - "Host ipv6\n" - "\tProxyJump [2620:52:0::fed]\n" - ""); + LIBSSH_TESTCONFIG_STRING11); /* RekeyLimit combinations */ torture_write_file(LIBSSH_TESTCONFIG12, - "Host default\n" - "\tRekeyLimit default none\n" - "Host data1\n" - "\tRekeyLimit 42G\n" - "Host data2\n" - "\tRekeyLimit 31M\n" - "Host data3\n" - "\tRekeyLimit 521K\n" - "Host time1\n" - "\tRekeyLimit default 3D\n" - "Host time2\n" - "\tRekeyLimit default 2h\n" - "Host time3\n" - "\tRekeyLimit default 160m\n" - "Host time4\n" - "\tRekeyLimit default 9600\n" - ""); - - torture_write_file(LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES, - "PubkeyAcceptedKeyTypes "PUBKEYACCEPTEDTYPES"\n"); + LIBSSH_TESTCONFIG_STRING12); - session = ssh_new(); + torture_write_file(LIBSSH_TEST_PUBKEYTYPES, + LIBSSH_TEST_PUBKEYTYPES_STRING); - verbosity = torture_libssh_verbosity(); - ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); + torture_write_file(LIBSSH_TEST_NONEWLINEEND, + LIBSSH_TEST_NONEWLINEEND_STRING); - *state = session; + torture_write_file(LIBSSH_TEST_NONEWLINEONELINE, + LIBSSH_TEST_NONEWLINEONELINE_STRING); return 0; } -static int teardown(void **state) +static int teardown_config_files(void **state) { + (void) state; /* unused */ + unlink(LIBSSH_TESTCONFIG1); unlink(LIBSSH_TESTCONFIG2); unlink(LIBSSH_TESTCONFIG3); @@ -215,27 +293,47 @@ static int teardown(void **state) unlink(LIBSSH_TESTCONFIG10); unlink(LIBSSH_TESTCONFIG11); unlink(LIBSSH_TESTCONFIG12); - unlink(LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES); + unlink(LIBSSH_TEST_PUBKEYTYPES); + return 0; +} + +static int setup(void **state) +{ + ssh_session session = NULL; + int verbosity; + + session = ssh_new(); + + verbosity = torture_libssh_verbosity(); + ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); + + *state = session; + + return 0; +} + +static int teardown(void **state) +{ ssh_free(*state); return 0; } /** - * @brief tests ssh_config_parse_file with Include directives + * @brief tests ssh config parsing with Include directives */ -static void torture_config_from_file(void **state) { - ssh_session session = *state; +static void torture_config_include(void **state, + const char *file, const char *string) +{ int ret; char *v = NULL; char *fips_algos = NULL; + ssh_session session = *state; - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG1); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); /* Test the variable presence */ - ret = ssh_options_get(session, SSH_OPTIONS_PROXYCOMMAND, &v); assert_true(ret == 0); assert_non_null(v); @@ -264,7 +362,8 @@ static void torture_config_from_file(void **state) { SAFE_FREE(fips_algos); fips_algos = ssh_keep_fips_algos(SSH_HOSTKEYS, HOSTKEYALGORITHMS); assert_non_null(fips_algos); - assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], fips_algos); + assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], + fips_algos); SAFE_FREE(fips_algos); fips_algos = ssh_keep_fips_algos(SSH_HOSTKEYS, PUBKEYACCEPTEDTYPES); assert_non_null(fips_algos); @@ -272,19 +371,24 @@ static void torture_config_from_file(void **state) { SAFE_FREE(fips_algos); fips_algos = ssh_keep_fips_algos(SSH_MAC_C_S, MACS); assert_non_null(fips_algos); - assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], fips_algos); + assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], + fips_algos); SAFE_FREE(fips_algos); fips_algos = ssh_keep_fips_algos(SSH_MAC_S_C, MACS); assert_non_null(fips_algos); - assert_string_equal(session->opts.wanted_methods[SSH_MAC_S_C], fips_algos); + assert_string_equal(session->opts.wanted_methods[SSH_MAC_S_C], + fips_algos); SAFE_FREE(fips_algos); } else { assert_non_null(session->opts.wanted_methods[SSH_KEX]); - assert_string_equal(session->opts.wanted_methods[SSH_KEX], KEXALGORITHMS); + assert_string_equal(session->opts.wanted_methods[SSH_KEX], + KEXALGORITHMS); assert_non_null(session->opts.wanted_methods[SSH_HOSTKEYS]); - assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], HOSTKEYALGORITHMS); + assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], + HOSTKEYALGORITHMS); assert_non_null(session->opts.pubkey_accepted_types); - assert_string_equal(session->opts.pubkey_accepted_types, PUBKEYACCEPTEDTYPES); + assert_string_equal(session->opts.pubkey_accepted_types, + PUBKEYACCEPTEDTYPES); assert_non_null(session->opts.wanted_methods[SSH_MAC_S_C]); assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], MACS); assert_non_null(session->opts.wanted_methods[SSH_MAC_S_C]); @@ -293,27 +397,49 @@ static void torture_config_from_file(void **state) { } /** + * @brief tests ssh_config_parse_file with Include directives from file + */ +static void torture_config_include_file(void **state) +{ + torture_config_include(state, LIBSSH_TESTCONFIG1, NULL); +} + +/** + * @brief tests ssh_config_parse_string with Include directives from string + */ +static void torture_config_include_string(void **state) +{ + torture_config_include(state, NULL, LIBSSH_TESTCONFIG_STRING1); +} + +/** * @brief tests ssh_config_parse_file with multiple Port settings. */ -static void torture_config_double_ports(void **state) { - ssh_session session = *state; - int ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG4); - assert_true(ret == 0); +static void torture_config_double_ports_file(void **state) +{ + _parse_config(*state, LIBSSH_TESTCONFIG4, NULL, SSH_OK); } -static void torture_config_glob(void **state) { - ssh_session session = *state; - int ret; +/** + * @brief tests ssh_config_parse_string with multiple Port settings. + */ +static void torture_config_double_ports_string(void **state) +{ + _parse_config(*state, NULL, LIBSSH_TESTCONFIG_STRING4, SSH_OK); +} + +static void torture_config_glob(void **state, + const char *file, const char *string) +{ #if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER) + int ret; char *v; -#endif /* HAVE_GLOB && HAVE_GLOB_GL_FLAGS_MEMBER */ + ssh_session session = *state; - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG5); - assert_true(ret == 0); /* non-existing files should not error */ + _parse_config(session, file, string, SSH_OK); /* Test the variable presence */ -#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER) ret = ssh_options_get(session, SSH_OPTIONS_PROXYCOMMAND, &v); assert_true(ret == 0); assert_non_null(v); @@ -330,16 +456,25 @@ static void torture_config_glob(void **state) { #endif /* HAVE_GLOB && HAVE_GLOB_GL_FLAGS_MEMBER */ } +static void torture_config_glob_file(void **state) +{ + torture_config_glob(state, LIBSSH_TESTCONFIG5, NULL); +} + +static void torture_config_glob_string(void **state) +{ + torture_config_glob(state, NULL, LIBSSH_TESTCONFIG_STRING5); +} + /** * @brief Verify the new options are passed from configuration */ -static void torture_config_new(void **state) +static void torture_config_new(void ** state, + const char *file, const char *string) { ssh_session session = *state; - int ret = 0; - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG7); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.knownhosts, USER_KNOWN_HOSTS); assert_string_equal(session->opts.global_knownhosts, GLOBAL_KNOWN_HOSTS); @@ -363,33 +498,40 @@ static void torture_config_new(void **state) assert_int_equal(session->common.log_verbosity, SSH_LOG_TRACE); } +static void torture_config_new_file(void **state) +{ + torture_config_new(state, LIBSSH_TESTCONFIG7, NULL); +} + +static void torture_config_new_string(void **state) +{ + torture_config_new(state, NULL, LIBSSH_TESTCONFIG_STRING7); +} + /** * @brief Verify the authentication methods from configuration are effective */ -static void torture_config_auth_methods(void **state) { +static void torture_config_auth_methods(void **state, + const char *file, const char *string) +{ ssh_session session = *state; - int ret = 0; /* gradually disable all the methods based on different hosts */ ssh_options_set(session, SSH_OPTIONS_HOST, "nogss"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_false(session->opts.flags & SSH_OPT_FLAG_GSSAPI_AUTH); assert_true(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH); ssh_options_set(session, SSH_OPTIONS_HOST, "nokbd"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_false(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH); ssh_options_set(session, SSH_OPTIONS_HOST, "nopass"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_false(session->opts.flags & SSH_OPT_FLAG_PASSWORD_AUTH); ssh_options_set(session, SSH_OPTIONS_HOST, "nopubkey"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_false(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH); /* no method should be left enabled */ @@ -398,39 +540,55 @@ static void torture_config_auth_methods(void **state) { /* gradually enable them again */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "gss"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_true(session->opts.flags & SSH_OPT_FLAG_GSSAPI_AUTH); assert_false(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH); ssh_options_set(session, SSH_OPTIONS_HOST, "kbd"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_true(session->opts.flags & SSH_OPT_FLAG_KBDINT_AUTH); ssh_options_set(session, SSH_OPTIONS_HOST, "pass"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_true(session->opts.flags & SSH_OPT_FLAG_PASSWORD_AUTH); ssh_options_set(session, SSH_OPTIONS_HOST, "pubkey"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8); - assert_true(ret == 0); + _parse_config(session, file, string, SSH_OK); assert_true(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH); } /** + * @brief Verify the authentication methods from configuration file + * are effective + */ +static void torture_config_auth_methods_file(void **state) +{ + torture_config_auth_methods(state, LIBSSH_TESTCONFIG8, NULL); +} + +/** + * @brief Verify the authentication methods from configuration string + * are effective + */ +static void torture_config_auth_methods_string(void **state) +{ + torture_config_auth_methods(state, NULL, LIBSSH_TESTCONFIG_STRING8); +} + +/** * @brief Verify the configuration parser does not choke on unknown * or unsupported configuration options */ -static void torture_config_unknown(void **state) { +static void torture_config_unknown(void **state, + const char *file, const char *string) +{ ssh_session session = *state; int ret = 0; /* test corner cases */ - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG9); - assert_true(ret == 0); - assert_string_equal(session->opts.ProxyCommand, "ssh -W [%h]:%p many-spaces.com"); + _parse_config(session, file, string, SSH_OK); + assert_string_equal(session->opts.ProxyCommand, + "ssh -W [%h]:%p many-spaces.com"); assert_string_equal(session->opts.host, "equal.sign"); ret = ssh_config_parse_file(session, "/etc/ssh/ssh_config"); @@ -439,128 +597,155 @@ static void torture_config_unknown(void **state) { assert_true(ret == 0); } +/** + * @brief Verify the configuration parser does not choke on unknown + * or unsupported configuration options in configuration file + */ +static void torture_config_unknown_file(void **state) +{ + torture_config_unknown(state, LIBSSH_TESTCONFIG9, NULL); +} + +/** + * @brief Verify the configuration parser does not choke on unknown + * or unsupported configuration options in configuration string + */ +static void torture_config_unknown_string(void **state) +{ + torture_config_unknown(state, NULL, LIBSSH_TESTCONFIG_STRING9); +} /** * @brief Verify the configuration parser accepts Match keyword with * full OpenSSH syntax. */ -static void torture_config_match(void **state) +static void torture_config_match(void **state, + const char *file, const char *string) { ssh_session session = *state; char *localuser = NULL; - char config[1024]; - int ret = 0; + const char *config; + char config_string[1024]; /* Without any settings we should get all-matched.com hostname */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "unmatched"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "all-matched.com"); /* Hostname example does simple hostname matching */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "example"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "example.com"); /* We can match also both hosts from a comma separated list */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "example1"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "exampleN"); torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "example2"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "exampleN"); /* We can match by user */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_USER, "guest"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "guest.com"); /* We can combine two options on a single line to match both of them */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_USER, "tester"); ssh_options_set(session, SSH_OPTIONS_HOST, "testhost"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "testhost.com"); /* We can also negate conditions */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_USER, "not-tester"); ssh_options_set(session, SSH_OPTIONS_HOST, "testhost"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "nonuser-testhost.com"); + /* In this part, we try various other config files and strings. */ + /* Match final is not completely supported, but should do quite much the * same as "match all". The trailing "all" is not mandatory. */ - torture_write_file(LIBSSH_TESTCONFIG10, - "Match final all\n" - "\tHostName final-all.com\n" - ""); + config = "Match final all\n" + "\tHostName final-all.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "final-all.com"); - torture_write_file(LIBSSH_TESTCONFIG10, - "Match final\n" - "\tHostName final.com\n" - ""); + config = "Match final\n" + "\tHostName final.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "final.com"); - /* Match canonical is not completely supported, but should do quite much the - * same as "match all". The trailing "all" is not mandatory. */ - torture_write_file(LIBSSH_TESTCONFIG10, - "Match canonical all\n" - "\tHostName canonical-all.com\n" - ""); + /* Match canonical is not completely supported, but should do quite + * much the same as "match all". The trailing "all" is not mandatory. */ + config = "Match canonical all\n" + "\tHostName canonical-all.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "canonical-all.com"); - torture_write_file(LIBSSH_TESTCONFIG10, - "Match canonical all\n" - "\tHostName canonical.com\n" - ""); + config = "Match canonical all\n" + "\tHostName canonical.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "canonical.com"); localuser = ssh_get_local_username(); assert_non_null(localuser); - snprintf(config, sizeof(config), + snprintf(config_string, sizeof(config_string), "Match localuser %s\n" - "\tHostName otherhost\n" - "", localuser); + "\tHostName otherhost\n", + localuser); + config = config_string; free(localuser); - torture_write_file(LIBSSH_TESTCONFIG10, config); + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.host, "otherhost"); - torture_write_file(LIBSSH_TESTCONFIG10, - "Match exec true\n" - "\tHostName execed-true.com\n" - ""); + config = "Match exec true\n" + "\tHostName execed-true.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); #ifdef _WIN32 /* The match exec is not supported on windows at this moment */ assert_string_equal(session->opts.host, "otherhost"); @@ -568,13 +753,15 @@ static void torture_config_match(void **state) assert_string_equal(session->opts.host, "execed-true.com"); #endif - torture_write_file(LIBSSH_TESTCONFIG10, - "Match !exec false\n" - "\tHostName execed-false.com\n" - ""); + config = "Match !exec false\n" + "\tHostName execed-false.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); #ifdef _WIN32 /* The match exec is not supported on windows at this moment */ assert_string_equal(session->opts.host, "otherhost"); @@ -582,13 +769,15 @@ static void torture_config_match(void **state) assert_string_equal(session->opts.host, "execed-false.com"); #endif - torture_write_file(LIBSSH_TESTCONFIG10, - "Match exec \"test 1 -eq 1\"\n" - "\tHostName execed-arguments.com\n" - ""); + config = "Match exec \"test 1 -eq 1\"\n" + "\tHostName execed-arguments.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); #ifdef _WIN32 /* The match exec is not supported on windows at this moment */ assert_string_equal(session->opts.host, "otherhost"); @@ -598,355 +787,435 @@ static void torture_config_match(void **state) /* Try to create some invalid configurations */ /* Missing argument to Match*/ - torture_write_file(LIBSSH_TESTCONFIG10, - "Match\n" - "\tHost missing.com\n" - ""); + config = "Match\n" + "\tHost missing.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing argument to unsupported option originalhost */ - torture_write_file(LIBSSH_TESTCONFIG10, - "Match originalhost\n" - "\tHost originalhost.com\n" - ""); + config = "Match originalhost\n" + "\tHost originalhost.com\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing argument to option localuser */ - torture_write_file(LIBSSH_TESTCONFIG10, - "Match localuser\n" - "\tUser localuser2\n" - ""); + config = "Match localuser\n" + "\tUser localuser2\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing argument to option user */ - torture_write_file(LIBSSH_TESTCONFIG10, - "Match user\n" - "\tUser user2\n" - ""); + config = "Match user\n" + "\tUser user2\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing argument to option host */ - torture_write_file(LIBSSH_TESTCONFIG10, - "Match host\n" - "\tUser host2\n" - ""); + config = "Match host\n" + "\tUser host2\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing argument to option exec */ - torture_write_file(LIBSSH_TESTCONFIG10, - "Match exec\n" - "\tUser exec\n" - ""); + config = "Match exec\n" + "\tUser exec\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); +} + +/** + * @brief Verify the configuration parser accepts Match keyword with + * full OpenSSH syntax through configuration file. + */ +static void torture_config_match_file(void **state) +{ + torture_config_match(state, LIBSSH_TESTCONFIG10, NULL); +} + +/** + * @brief Verify the configuration parser accepts Match keyword with + * full OpenSSH syntax through configuration string. + */ +static void torture_config_match_string(void **state) +{ + torture_config_match(state, NULL, LIBSSH_TESTCONFIG_STRING10); } /** * @brief Verify we can parse ProxyJump configuration option */ -static void torture_config_proxyjump(void **state) { +static void torture_config_proxyjump(void **state, + const char *file, const char *string) +{ ssh_session session = *state; - int ret = 0; + const char *config; /* Simplest version with just a hostname */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "simple"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.ProxyCommand, "ssh -W [%h]:%p jumpbox"); /* With username */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "user"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.ProxyCommand, "ssh -l user -W [%h]:%p jumpbox"); /* With port */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "port"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.ProxyCommand, "ssh -p 2222 -W [%h]:%p jumpbox"); /* Two step jump */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "two-step"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.ProxyCommand, "ssh -l u1 -p 222 -J u2@second:33 -W [%h]:%p first"); /* none */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "none"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_true(session->opts.ProxyCommand == NULL); /* If also ProxyCommand is specifed, the first is applied */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "only-command"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.ProxyCommand, PROXYCMD); /* If also ProxyCommand is specifed, the first is applied */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "only-jump"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.ProxyCommand, "ssh -W [%h]:%p jumpbox"); /* IPv6 address */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "ipv6"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_string_equal(session->opts.ProxyCommand, "ssh -W [%h]:%p 2620:52:0::fed"); + /* In this part, we try various other config files and strings. */ + /* Try to create some invalid configurations */ /* Non-numeric port */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host bad-port\n" - "\tProxyJump jumpbox:22bad22\n" - ""); + config = "Host bad-port\n" + "\tProxyJump jumpbox:22bad22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "bad-port"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Too many @ */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host bad-hostname\n" - "\tProxyJump user@principal.com@jumpbox:22\n" - ""); + config = "Host bad-hostname\n" + "\tProxyJump user@principal.com@jumpbox:22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "bad-hostname"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Braces mismatch in hostname */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host mismatch\n" - "\tProxyJump [::1\n" - ""); + config = "Host mismatch\n" + "\tProxyJump [::1\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "mismatch"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Bad host-port separator */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host beef\n" - "\tProxyJump [dead::beef]::22\n" - ""); + config = "Host beef\n" + "\tProxyJump [dead::beef]::22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "beef"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing hostname */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host no-host\n" - "\tProxyJump user@:22\n" - ""); + config = "Host no-host\n" + "\tProxyJump user@:22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "no-host"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing user */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host no-user\n" - "\tProxyJump @host:22\n" - ""); + config = "Host no-user\n" + "\tProxyJump @host:22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "no-user"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing port */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host no-port\n" - "\tProxyJump host:\n" - ""); + config = "Host no-port\n" + "\tProxyJump host:\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "no-port"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Non-numeric port in second jump */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host bad-port-2\n" - "\tProxyJump localhost,jumpbox:22bad22\n" - ""); + config = "Host bad-port-2\n" + "\tProxyJump localhost,jumpbox:22bad22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "bad-port-2"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Too many @ in second jump */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host bad-hostname\n" - "\tProxyJump localhost,user@principal.com@jumpbox:22\n" - ""); + config = "Host bad-hostname\n" + "\tProxyJump localhost,user@principal.com@jumpbox:22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "bad-hostname"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Braces mismatch in second jump */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host mismatch\n" - "\tProxyJump localhost,[::1:20\n" - ""); + config = "Host mismatch\n" + "\tProxyJump localhost,[::1:20\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "mismatch"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Bad host-port separator in second jump */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host beef\n" - "\tProxyJump localhost,[dead::beef]::22\n" - ""); + config = "Host beef\n" + "\tProxyJump localhost,[dead::beef]::22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "beef"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing hostname in second jump */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host no-host\n" - "\tProxyJump localhost,user@:22\n" - ""); + config = "Host no-host\n" + "\tProxyJump localhost,user@:22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "no-host"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing user in second jump */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host no-user\n" - "\tProxyJump localhost,@host:22\n" - ""); + config = "Host no-user\n" + "\tProxyJump localhost,@host:22\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "no-user"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); /* Missing port in second jump */ - torture_write_file(LIBSSH_TESTCONFIG11, - "Host no-port\n" - "\tProxyJump localhost,host:\n" - ""); + config = "Host no-port\n" + "\tProxyJump localhost,host:\n"; + if (file != NULL) { + torture_write_file(file, config); + } else { + string = config; + } torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "no-port"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG11); - assert_ssh_return_code_equal(session, ret, SSH_ERROR); + _parse_config(session, file, string, SSH_ERROR); +} + +/** + * @brief Verify we can parse ProxyJump configuration option from file + */ +static void torture_config_proxyjump_file(void **state) +{ + torture_config_proxyjump(state, LIBSSH_TESTCONFIG11, NULL); +} + +/** + * @brief Verify we can parse ProxyJump configuration option from string + */ +static void torture_config_proxyjump_string(void **state) +{ + torture_config_proxyjump(state, NULL, LIBSSH_TESTCONFIG_STRING11); } /** * @brief Verify the configuration parser handles all the possible * versions of RekeyLimit configuration option. */ -static void torture_config_rekey(void **state) +static void torture_config_rekey(void **state, + const char *file, const char *string) { ssh_session session = *state; - int ret = 0; /* Default values */ ssh_options_set(session, SSH_OPTIONS_HOST, "default"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_int_equal(session->opts.rekey_data, 0); assert_int_equal(session->opts.rekey_time, 0); /* 42 GB */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "data1"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12); - assert_ssh_return_code(session, ret); - assert_int_equal(session->opts.rekey_data, (uint64_t) 42 * 1024 * 1024 * 1024); + _parse_config(session, file, string, SSH_OK); + assert_int_equal(session->opts.rekey_data, + (uint64_t) 42 * 1024 * 1024 * 1024); assert_int_equal(session->opts.rekey_time, 0); /* 41 MB */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "data2"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_int_equal(session->opts.rekey_data, 31 * 1024 * 1024); assert_int_equal(session->opts.rekey_time, 0); /* 521 KB */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "data3"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_int_equal(session->opts.rekey_data, 521 * 1024); assert_int_equal(session->opts.rekey_time, 0); /* default 3D */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "time1"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_int_equal(session->opts.rekey_data, 0); assert_int_equal(session->opts.rekey_time, 3 * 24 * 60 * 60 * 1000); /* default 2h */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "time2"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_int_equal(session->opts.rekey_data, 0); assert_int_equal(session->opts.rekey_time, 2 * 60 * 60 * 1000); /* default 160m */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "time3"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_int_equal(session->opts.rekey_data, 0); assert_int_equal(session->opts.rekey_time, 160 * 60 * 1000); /* default 9600 [s] */ torture_reset_config(session); ssh_options_set(session, SSH_OPTIONS_HOST, "time4"); - ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG12); - assert_ssh_return_code(session, ret); + _parse_config(session, file, string, SSH_OK); assert_int_equal(session->opts.rekey_data, 0); assert_int_equal(session->opts.rekey_time, 9600 * 1000); } /** - * @brief test ssh_config_parse_file with PubkeyAcceptedKeyTypes + * @brief Verify the configuration parser handles all the possible + * versions of RekeyLimit configuration option in file + */ +static void torture_config_rekey_file(void **state) +{ + torture_config_rekey(state, LIBSSH_TESTCONFIG12, NULL); +} + +/** + * @brief Verify the configuration parser handles all the possible + * versions of RekeyLimit configuration option in string + */ +static void torture_config_rekey_string(void **state) +{ + torture_config_rekey(state, NULL, LIBSSH_TESTCONFIG_STRING12); +} + +/** + * @brief test PubkeyAcceptedKeyTypes helper function */ -static void torture_config_pubkeyacceptedkeytypes(void **state) +static void torture_config_pubkeytypes(void **state, + const char *file, const char *string) { ssh_session session = *state; - int rc; char *fips_algos; - rc = ssh_config_parse_file(session, LIBSSH_TEST_PUBKEYACCEPTEDKEYTYPES); - assert_int_equal(rc, SSH_OK); + _parse_config(session, file, string, SSH_OK); if (ssh_fips_mode()) { fips_algos = ssh_keep_fips_algos(SSH_HOSTKEYS, PUBKEYACCEPTEDTYPES); @@ -954,10 +1223,85 @@ static void torture_config_pubkeyacceptedkeytypes(void **state) assert_string_equal(session->opts.pubkey_accepted_types, fips_algos); SAFE_FREE(fips_algos); } else { - assert_string_equal(session->opts.pubkey_accepted_types, PUBKEYACCEPTEDTYPES); + assert_string_equal(session->opts.pubkey_accepted_types, + PUBKEYACCEPTEDTYPES); } } +/** + * @brief test parsing PubkeyAcceptedKeyTypes from file + */ +static void torture_config_pubkeytypes_file(void **state) +{ + torture_config_pubkeytypes(state, LIBSSH_TEST_PUBKEYTYPES, NULL); +} + +/** + * @brief test parsing PubkeyAcceptedKeyTypes from string + */ +static void torture_config_pubkeytypes_string(void **state) +{ + torture_config_pubkeytypes(state, NULL, LIBSSH_TEST_PUBKEYTYPES_STRING); +} + +/** + * @brief Verify the configuration parser handles + * missing newline in the end + */ +static void torture_config_nonewlineend(void **state, + const char *file, const char *string) +{ + _parse_config(*state, file, string, SSH_OK); +} + +/** + * @brief Verify the configuration parser handles + * missing newline in the end of file + */ +static void torture_config_nonewlineend_file(void **state) +{ + torture_config_nonewlineend(state, LIBSSH_TEST_NONEWLINEEND, NULL); +} + +/** + * @brief Verify the configuration parser handles + * missing newline in the end of string + */ +static void torture_config_nonewlineend_string(void **state) +{ + torture_config_nonewlineend(state, NULL, LIBSSH_TEST_NONEWLINEEND_STRING); +} + +/** + * @brief Verify the configuration parser handles + * missing newline in the end + */ +static void torture_config_nonewlineoneline(void **state, + const char *file, + const char *string) +{ + _parse_config(*state, file, string, SSH_OK); +} + +/** + * @brief Verify the configuration parser handles + * missing newline in the end of file + */ +static void torture_config_nonewlineoneline_file(void **state) +{ + torture_config_nonewlineend(state, LIBSSH_TEST_NONEWLINEONELINE, NULL); +} + +/** + * @brief Verify the configuration parser handles + * missing newline in the end of string + */ +static void torture_config_nonewlineoneline_string(void **state) +{ + torture_config_nonewlineoneline(state, + NULL, LIBSSH_TEST_NONEWLINEONELINE_STRING); +} + /* ssh_config_get_cmd() does three things: * * Strips leading whitespace * * Terminate the characted on the end of next quotes-enclosed string @@ -994,7 +1338,8 @@ static void torture_config_parser_get_cmd(void **state) assert_string_equal(tok, "something"); assert_int_equal(*p, '\0'); - /* But it does not split tokens by whitespace if they are not quoted, which is weird */ + /* But it does not split tokens by whitespace + * if they are not quoted, which is weird */ strncpy(data, "multi string something\n", sizeof(data)); p = data; tok = ssh_config_get_cmd(&p); @@ -1004,7 +1349,8 @@ static void torture_config_parser_get_cmd(void **state) /* ssh_config_get_token() should behave as expected * * Strip leading whitespace - * * Return first token separated by whitespace or equal sign, respecting quotes! + * * Return first token separated by whitespace or equal sign, + * respecting quotes! */ static void torture_config_parser_get_token(void **state) { @@ -1206,7 +1552,8 @@ static void torture_config_match_pattern(void **state) assert_int_equal(rv, 1); rv = match_pattern("aa", "?", MAX_MATCH_RECURSION); assert_int_equal(rv, 0); - rv = match_pattern("?", "a", MAX_MATCH_RECURSION); /* Wildcard in search string */ + /* Wildcard in search string */ + rv = match_pattern("?", "a", MAX_MATCH_RECURSION); assert_int_equal(rv, 0); rv = match_pattern("?", "?", MAX_MATCH_RECURSION); assert_int_equal(rv, 1); @@ -1216,7 +1563,8 @@ static void torture_config_match_pattern(void **state) assert_int_equal(rv, 1); rv = match_pattern("aa", "*", MAX_MATCH_RECURSION); assert_int_equal(rv, 1); - rv = match_pattern("*", "a", MAX_MATCH_RECURSION); /* Wildcard in search string */ + /* Wildcard in search string */ + rv = match_pattern("*", "a", MAX_MATCH_RECURSION); assert_int_equal(rv, 0); rv = match_pattern("*", "*", MAX_MATCH_RECURSION); assert_int_equal(rv, 1); @@ -1256,34 +1604,78 @@ static void torture_config_match_pattern(void **state) /* Limit the maximum recursion */ rv = match_pattern("hostname", "*p*a*t*t*e*r*n*", 5); assert_int_equal(rv, 0); - rv = match_pattern("pattern", "*p*a*t*t*e*r*n*", 5); /* Too much recursion */ + /* Too much recursion */ + rv = match_pattern("pattern", "*p*a*t*t*e*r*n*", 5); assert_int_equal(rv, 0); } -int torture_run_tests(void) { +int torture_run_tests(void) +{ int rc; struct CMUnitTest tests[] = { - cmocka_unit_test(torture_config_from_file), - cmocka_unit_test(torture_config_double_ports), - cmocka_unit_test(torture_config_glob), - cmocka_unit_test(torture_config_new), - cmocka_unit_test(torture_config_auth_methods), - cmocka_unit_test(torture_config_unknown), - cmocka_unit_test(torture_config_match), - cmocka_unit_test(torture_config_proxyjump), - cmocka_unit_test(torture_config_rekey), - cmocka_unit_test(torture_config_pubkeyacceptedkeytypes), - cmocka_unit_test(torture_config_parser_get_cmd), - cmocka_unit_test(torture_config_parser_get_token), - cmocka_unit_test(torture_config_match_pattern), + cmocka_unit_test_setup_teardown(torture_config_include_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_include_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_double_ports_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_double_ports_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_glob_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_glob_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_new_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_new_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_auth_methods_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_auth_methods_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_unknown_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_unknown_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_match_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_match_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_proxyjump_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_proxyjump_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_rekey_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_rekey_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_pubkeytypes_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_pubkeytypes_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_nonewlineend_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_nonewlineend_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_nonewlineoneline_file, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_nonewlineoneline_string, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_parser_get_cmd, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_parser_get_token, + setup, teardown), + cmocka_unit_test_setup_teardown(torture_config_match_pattern, + setup, teardown), }; ssh_init(); torture_filter_tests(tests); - rc = cmocka_run_group_tests(tests, setup_config_files, teardown); + rc = cmocka_run_group_tests(tests, + setup_config_files, teardown_config_files); ssh_finalize(); return rc; } |