diff --git a/include/libssh/bind.h b/include/libssh/bind.h index edbc7b77..c082e199 100644 --- a/include/libssh/bind.h +++ b/include/libssh/bind.h @@ -46,6 +46,7 @@ struct ssh_bind_struct { unsigned int bindport; int blocking; int toaccept; + bool config_processed; }; struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct diff --git a/include/libssh/server.h b/include/libssh/server.h index 9fe73575..f1d905d0 100644 --- a/include/libssh/server.h +++ b/include/libssh/server.h @@ -90,6 +90,9 @@ LIBSSH_API ssh_bind ssh_bind_new(void); LIBSSH_API int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, const void *value); +LIBSSH_API int ssh_bind_options_parse_config(ssh_bind sshbind, + const char *filename); + /** * @brief Start listening to the socket. * diff --git a/src/options.c b/src/options.c index bdbdcb0e..a61f8a48 100644 --- a/src/options.c +++ b/src/options.c @@ -39,6 +39,7 @@ #ifdef WITH_SERVER #include "libssh/server.h" #include "libssh/bind.h" +#include "libssh/bind_config.h" #endif /** @@ -1894,6 +1895,49 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, return 0; } + +/** + * @brief Parse a ssh bind options configuration file. + * + * This parses the options file and set them to the ssh_bind handle provided. If + * an option was previously set, it is overridden. If the global configuration + * hasn't been processed yet, it is processed prior to the provided file. + * + * @param sshbind SSH bind handle + * + * @param filename The options file to use; if NULL only the global + * configuration is parsed and applied (if it haven't been + * processed before). + * + * @return 0 on success, < 0 on error. + */ +int ssh_bind_options_parse_config(ssh_bind sshbind, const char *filename) +{ + int rc = 0; + + if (sshbind == NULL) { + return -1; + } + + /* If the global default configuration hasn't been processed yet, process it + * before the provided configuration. */ + if (!(sshbind->config_processed)) { + rc = ssh_bind_config_parse_file(sshbind, + "/etc/ssh/libssh_server_config"); + if (rc != 0) { + return rc; + } + sshbind->config_processed = true; + } + + if (filename != NULL) { + /* Apply the user provided configuration */ + rc = ssh_bind_config_parse_file(sshbind, filename); + } + + return rc; +} + #endif /** @} */ diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c index b6cc6f17..0337db43 100644 --- a/tests/unittests/torture_options.c +++ b/tests/unittests/torture_options.c @@ -15,6 +15,7 @@ #include #ifdef WITH_SERVER #include +#define LIBSSH_CUSTOM_BIND_CONFIG_FILE "my_bind_config" #endif #ifdef HAVE_DSA #define LIBSSH_DSA_TESTKEY "libssh_testkey.id_dsa" @@ -751,7 +752,7 @@ struct bind_st { ssh_bind bind; }; -static int setup_key_files(void **state) +static int ssh_bind_setup_files(void **state) { struct bind_st *test_state = NULL; char *cwd = NULL; @@ -792,6 +793,8 @@ static int setup_key_files(void **state) torture_write_file(LIBSSH_DSA_TESTKEY, torture_get_openssh_testkey(SSH_KEYTYPE_DSS, 0, 0)); #endif + torture_write_file(LIBSSH_CUSTOM_BIND_CONFIG_FILE, + "Port 42\n"); return 0; } @@ -802,7 +805,7 @@ static int sshbind_setup(void **state) int rc; struct bind_st *test_state = NULL; - rc = setup_key_files((void **)&test_state); + rc = ssh_bind_setup_files((void **)&test_state); assert_int_equal(rc, 0); assert_non_null(test_state); @@ -1294,6 +1297,23 @@ static void torture_bind_options_set_macs(void **state) assert_int_not_equal(rc, 0); } +static void torture_bind_options_parse_config(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + int rc; + + assert_non_null(state); + test_state = *((struct bind_st **)state); + assert_non_null(test_state); + assert_non_null(test_state->bind); + bind = test_state->bind; + + rc = ssh_bind_options_parse_config(bind, LIBSSH_CUSTOM_BIND_CONFIG_FILE); + assert_int_equal(rc, 0); + assert_int_equal(bind->bindport, 42); +} + #endif /* WITH_SERVER */ @@ -1359,6 +1379,8 @@ int torture_run_tests(void) { sshbind_setup, sshbind_teardown), cmocka_unit_test_setup_teardown(torture_bind_options_set_macs, sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_options_parse_config, + sshbind_setup, sshbind_teardown), }; #endif /* WITH_SERVER */