aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libssh/bind.h1
-rw-r--r--include/libssh/server.h3
-rw-r--r--src/bind.c1
-rw-r--r--src/options.c104
-rw-r--r--tests/unittests/torture_options.c47
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;
diff --git a/src/bind.c b/src/bind.c
index 6d3f325d..b20f7fb3 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -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 */