diff options
author | Anderson Toshiyuki Sasaki <ansasaki@redhat.com> | 2019-03-07 13:04:29 +0100 |
---|---|---|
committer | Andreas Schneider <asn@cryptomilk.org> | 2019-04-01 08:38:17 +0200 |
commit | 68385a2e983a30c3013663e4cc934a67a9878ea5 (patch) | |
tree | c4338d509bfefdc549b5f54548f94ec257809727 | |
parent | fd25beff68a8c61c62a1f43eb1c53d50a7390180 (diff) | |
download | libssh-68385a2e983a30c3013663e4cc934a67a9878ea5.tar.gz libssh-68385a2e983a30c3013663e4cc934a67a9878ea5.tar.xz libssh-68385a2e983a30c3013663e4cc934a67a9878ea5.zip |
options: Add a bind option to set the config directory
This adds the SSH_BIND_OPTIONS_CONFIG_DIR which allows to set the
directory used to expand the escape character "%d" when passing a path
to ssh_bind_options_parse_file().
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
-rw-r--r-- | include/libssh/bind.h | 1 | ||||
-rw-r--r-- | include/libssh/server.h | 3 | ||||
-rw-r--r-- | src/bind.c | 1 | ||||
-rw-r--r-- | src/options.c | 104 | ||||
-rw-r--r-- | tests/unittests/torture_options.c | 47 |
5 files changed, 153 insertions, 3 deletions
diff --git a/include/libssh/bind.h b/include/libssh/bind.h index c082e199..b22a8c7b 100644 --- a/include/libssh/bind.h +++ b/include/libssh/bind.h @@ -47,6 +47,7 @@ struct ssh_bind_struct { int blocking; int toaccept; bool config_processed; + char *config_dir; }; 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 f1d905d0..64e7ca87 100644 --- a/include/libssh/server.h +++ b/include/libssh/server.h @@ -51,7 +51,8 @@ enum ssh_bind_options_e { SSH_BIND_OPTIONS_CIPHERS_C_S, SSH_BIND_OPTIONS_CIPHERS_S_C, SSH_BIND_OPTIONS_HMAC_C_S, - SSH_BIND_OPTIONS_HMAC_S_C + SSH_BIND_OPTIONS_HMAC_S_C, + SSH_BIND_OPTIONS_CONFIG_DIR, }; typedef struct ssh_bind_struct* ssh_bind; @@ -393,6 +393,7 @@ void ssh_bind_free(ssh_bind sshbind){ /* options */ SAFE_FREE(sshbind->banner); SAFE_FREE(sshbind->bindaddr); + SAFE_FREE(sshbind->config_dir); SAFE_FREE(sshbind->dsakey); SAFE_FREE(sshbind->rsakey); diff --git a/src/options.c b/src/options.c index a61f8a48..fda73d62 100644 --- a/src/options.c +++ b/src/options.c @@ -1602,6 +1602,11 @@ static int ssh_bind_set_algo(ssh_bind sshbind, * Set the Message Authentication Code algorithm server * to client (const char *, comma-separated list). * + * - SSH_BIND_OPTIONS_CONFIG_DIR: + * Set the directory (const char *, format string) + * to be used when the "%d" scape is used when providing + * paths of configuration files to + * ssh_bind_options_parse_config(). * * @param value The value to set. This is a generic pointer and the * datatype which should be used is described at the @@ -1887,6 +1892,22 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, return -1; } break; + case SSH_BIND_OPTIONS_CONFIG_DIR: + v = value; + SAFE_FREE(sshbind->config_dir); + if (v == NULL) { + break; + } else if (v[0] == '\0') { + ssh_set_error_invalid(sshbind); + return -1; + } else { + sshbind->config_dir = ssh_path_expand_tilde(v); + if (sshbind->config_dir == NULL) { + ssh_set_error_oom(sshbind); + return -1; + } + } + break; default: ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); return -1; @@ -1896,6 +1917,80 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, return 0; } +static char *ssh_bind_options_expand_escape(ssh_bind sshbind, const char *s) +{ + char buf[MAX_BUF_SIZE]; + char *r, *x = NULL; + const char *p; + size_t i, l; + + r = ssh_path_expand_tilde(s); + if (r == NULL) { + ssh_set_error_oom(sshbind); + return NULL; + } + + if (strlen(r) > MAX_BUF_SIZE) { + ssh_set_error(sshbind, SSH_FATAL, "string to expand too long"); + free(r); + return NULL; + } + + p = r; + buf[0] = '\0'; + + for (i = 0; *p != '\0'; p++) { + if (*p != '%') { + buf[i] = *p; + i++; + if (i >= MAX_BUF_SIZE) { + free(r); + return NULL; + } + buf[i] = '\0'; + continue; + } + + p++; + if (*p == '\0') { + break; + } + + switch (*p) { + case 'd': + x = strdup(sshbind->config_dir); + break; + default: + ssh_set_error(sshbind, SSH_FATAL, + "Wrong escape sequence detected"); + free(r); + return NULL; + } + + if (x == NULL) { + ssh_set_error_oom(sshbind); + free(r); + return NULL; + } + + i += strlen(x); + if (i >= MAX_BUF_SIZE) { + ssh_set_error(sshbind, SSH_FATAL, + "String too long"); + free(x); + free(r); + return NULL; + } + l = strlen(buf); + strncpy(buf + l, x, sizeof(buf) - l - 1); + buf[i] = '\0'; + SAFE_FREE(x); + } + + free(r); + return strdup(buf); +} + /** * @brief Parse a ssh bind options configuration file. * @@ -1914,6 +2009,7 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type, int ssh_bind_options_parse_config(ssh_bind sshbind, const char *filename) { int rc = 0; + char *expanded_filename; if (sshbind == NULL) { return -1; @@ -1931,8 +2027,14 @@ int ssh_bind_options_parse_config(ssh_bind sshbind, const char *filename) } if (filename != NULL) { + expanded_filename = ssh_bind_options_expand_escape(sshbind, filename); + if (expanded_filename == NULL) { + return -1; + } + /* Apply the user provided configuration */ - rc = ssh_bind_config_parse_file(sshbind, filename); + rc = ssh_bind_config_parse_file(sshbind, expanded_filename); + free(expanded_filename); } return rc; diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c index 0337db43..a7140b7c 100644 --- a/tests/unittests/torture_options.c +++ b/tests/unittests/torture_options.c @@ -1301,6 +1301,7 @@ static void torture_bind_options_parse_config(void **state) { struct bind_st *test_state; ssh_bind bind; + char *cwd = NULL; int rc; assert_non_null(state); @@ -1309,11 +1310,53 @@ static void torture_bind_options_parse_config(void **state) assert_non_null(test_state->bind); bind = test_state->bind; - rc = ssh_bind_options_parse_config(bind, LIBSSH_CUSTOM_BIND_CONFIG_FILE); + cwd = torture_get_current_working_dir(); + assert_non_null(cwd); + + rc = ssh_bind_options_set(bind, + SSH_BIND_OPTIONS_CONFIG_DIR, + (const char *)cwd); + assert_int_equal(rc, 0); + assert_non_null(bind->config_dir); + assert_string_equal(bind->config_dir, cwd); + + rc = ssh_bind_options_parse_config(bind, "%d/"LIBSSH_CUSTOM_BIND_CONFIG_FILE); assert_int_equal(rc, 0); assert_int_equal(bind->bindport, 42); + + SAFE_FREE(cwd); +} + +static void torture_bind_options_config_dir(void **state) +{ + struct bind_st *test_state; + ssh_bind bind; + const char *new_dir = "/new/dir/"; + const char *replacement_dir = "/replacement/dir/"; + 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_set(bind, + SSH_BIND_OPTIONS_CONFIG_DIR, + new_dir); + assert_int_equal(rc, 0); + assert_non_null(bind->config_dir); + assert_string_equal(bind->config_dir, new_dir); + + rc = ssh_bind_options_set(bind, + SSH_BIND_OPTIONS_CONFIG_DIR, + replacement_dir); + assert_int_equal(rc, 0); + assert_non_null(bind->config_dir); + assert_string_equal(bind->config_dir, replacement_dir); } + #endif /* WITH_SERVER */ @@ -1381,6 +1424,8 @@ int torture_run_tests(void) { sshbind_setup, sshbind_teardown), cmocka_unit_test_setup_teardown(torture_bind_options_parse_config, sshbind_setup, sshbind_teardown), + cmocka_unit_test_setup_teardown(torture_bind_options_config_dir, + sshbind_setup, sshbind_teardown), }; #endif /* WITH_SERVER */ |