aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libssh/config.h66
-rw-r--r--include/libssh/session.h3
-rw-r--r--src/config.c80
-rw-r--r--src/session.c1
-rw-r--r--tests/client/torture_client_config.c8
-rw-r--r--tests/torture.c4
-rw-r--r--tests/torture.h2
-rw-r--r--tests/unittests/torture_config.c15
-rw-r--r--tests/unittests/torture_options.c24
9 files changed, 108 insertions, 95 deletions
diff --git a/include/libssh/config.h b/include/libssh/config.h
new file mode 100644
index 00000000..ce78f4ef
--- /dev/null
+++ b/include/libssh/config.h
@@ -0,0 +1,66 @@
+/*
+ * config.h - parse the ssh config file
+ *
+ * This file is part of the SSH Library
+ *
+ * Copyright (c) 2009-2018 by Andreas Schneider <asn@cryptomilk.org>
+ *
+ * The SSH Library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The SSH Library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the SSH Library; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef LIBSSH_CONFIG_H_
+#define LIBSSH_CONFIG_H_
+
+
+enum ssh_config_opcode_e {
+ /* Unknown opcode */
+ SOC_UNKNOWN = -3,
+ /* Known and not applicable to libssh */
+ SOC_NA = -2,
+ /* Known but not supported by current libssh version */
+ SOC_UNSUPPORTED = -1,
+ SOC_HOST,
+ SOC_MATCH,
+ SOC_HOSTNAME,
+ SOC_PORT,
+ SOC_USERNAME,
+ SOC_IDENTITY,
+ SOC_CIPHERS,
+ SOC_MACS,
+ SOC_COMPRESSION,
+ SOC_TIMEOUT,
+ SOC_PROTOCOL,
+ SOC_STRICTHOSTKEYCHECK,
+ SOC_KNOWNHOSTS,
+ SOC_PROXYCOMMAND,
+ SOC_GSSAPISERVERIDENTITY,
+ SOC_GSSAPICLIENTIDENTITY,
+ SOC_GSSAPIDELEGATECREDENTIALS,
+ SOC_INCLUDE,
+ SOC_BINDADDRESS,
+ SOC_GLOBALKNOWNHOSTSFILE,
+ SOC_LOGLEVEL,
+ SOC_HOSTKEYALGORITHMS,
+ SOC_KEXALGORITHMS,
+ SOC_GSSAPIAUTHENTICATION,
+ SOC_KBDINTERACTIVEAUTHENTICATION,
+ SOC_PASSWORDAUTHENTICATION,
+ SOC_PUBKEYAUTHENTICATION,
+ SOC_PUBKEYACCEPTEDTYPES,
+
+ SOC_MAX /* Keep this one last in the list */
+};
+#endif /* LIBSSH_CONFIG_H_ */
diff --git a/include/libssh/session.h b/include/libssh/session.h
index c846dc47..f0ad951b 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -29,6 +29,7 @@
#include "libssh/auth.h"
#include "libssh/channels.h"
#include "libssh/poll.h"
+#include "libssh/config.h"
/* These are the different states a SSH session can be into its life */
enum ssh_session_state_e {
@@ -220,7 +221,7 @@ struct ssh_session_struct {
int flags;
int nodelay;
bool config_processed;
- uint8_t *options_seen;
+ uint8_t options_seen[SOC_MAX];
} opts;
/* counters */
ssh_counter socket_counter;
diff --git a/src/config.c b/src/config.c
index ccb0c75b..121d042f 100644
--- a/src/config.c
+++ b/src/config.c
@@ -32,6 +32,7 @@
#endif
#include <stdbool.h>
+#include "libssh/config.h"
#include "libssh/priv.h"
#include "libssh/session.h"
#include "libssh/misc.h"
@@ -39,45 +40,6 @@
#define MAX_LINE_SIZE 1024
-enum ssh_config_opcode_e {
- /* Unknown opcode */
- SOC_UNKNOWN = -3,
- /* Known and not applicable to libssh */
- SOC_NA = -2,
- /* Known but not supported by current libssh version */
- SOC_UNSUPPORTED = -1,
- SOC_HOST,
- SOC_MATCH,
- SOC_HOSTNAME,
- SOC_PORT,
- SOC_USERNAME,
- SOC_IDENTITY,
- SOC_CIPHERS,
- SOC_MACS,
- SOC_COMPRESSION,
- SOC_TIMEOUT,
- SOC_PROTOCOL,
- SOC_STRICTHOSTKEYCHECK,
- SOC_KNOWNHOSTS,
- SOC_PROXYCOMMAND,
- SOC_GSSAPISERVERIDENTITY,
- SOC_GSSAPICLIENTIDENTITY,
- SOC_GSSAPIDELEGATECREDENTIALS,
- SOC_INCLUDE,
- SOC_BINDADDRESS,
- SOC_GLOBALKNOWNHOSTSFILE,
- SOC_LOGLEVEL,
- SOC_HOSTKEYALGORITHMS,
- SOC_KEXALGORITHMS,
- SOC_GSSAPIAUTHENTICATION,
- SOC_KBDINTERACTIVEAUTHENTICATION,
- SOC_PASSWORDAUTHENTICATION,
- SOC_PUBKEYAUTHENTICATION,
- SOC_PUBKEYACCEPTEDTYPES,
-
- SOC_END /* Keep this one last in the list */
-};
-
struct ssh_config_keyword_table_s {
const char *name;
enum ssh_config_opcode_e opcode;
@@ -213,7 +175,7 @@ static struct ssh_config_match_keyword_table_s ssh_config_match_keyword_table[]
};
static int ssh_config_parse_line(ssh_session session, const char *line,
- unsigned int count, int *parsing, uint8_t *seen);
+ unsigned int count, int *parsing);
static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
int i;
@@ -326,8 +288,7 @@ static int ssh_config_get_yesno(char **str, int notfound) {
static void
local_parse_file(ssh_session session,
const char *filename,
- int *parsing,
- uint8_t *seen)
+ int *parsing)
{
FILE *f;
char line[MAX_LINE_SIZE] = {0};
@@ -344,7 +305,7 @@ local_parse_file(ssh_session session,
SSH_LOG(SSH_LOG_PACKET, "Reading additional configuration data from %s", filename);
while (fgets(line, sizeof(line), f)) {
count++;
- rv = ssh_config_parse_line(session, line, count, parsing, seen);
+ rv = ssh_config_parse_line(session, line, count, parsing);
if (rv < 0) {
fclose(f);
return;
@@ -358,8 +319,7 @@ local_parse_file(ssh_session session,
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
static void local_parse_glob(ssh_session session,
const char *fileglob,
- int *parsing,
- uint8_t *seen)
+ int *parsing)
{
glob_t globbuf = {
.gl_flags = 0,
@@ -379,7 +339,7 @@ static void local_parse_glob(ssh_session session,
}
for (i = 0; i < globbuf.gl_pathc; i++) {
- local_parse_file(session, globbuf.gl_pathv[i], parsing, seen);
+ local_parse_file(session, globbuf.gl_pathv[i], parsing);
}
globfree(&globbuf);
@@ -420,8 +380,11 @@ ssh_config_match(char *value, const char *pattern, bool negate)
return result;
}
-static int ssh_config_parse_line(ssh_session session, const char *line,
- unsigned int count, int *parsing, uint8_t *seen)
+static int
+ssh_config_parse_line(ssh_session session,
+ const char *line,
+ unsigned int count,
+ int *parsing)
{
enum ssh_config_opcode_e opcode;
const char *p;
@@ -430,6 +393,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
char *lowerhost;
size_t len;
int i;
+ uint8_t *seen = session->opts.options_seen;
long l;
x = s = strdup(line);
@@ -473,9 +437,9 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
p = ssh_config_get_str_tok(&s, NULL);
if (p && *parsing) {
#if defined(HAVE_GLOB) && defined(HAVE_GLOB_GL_FLAGS_MEMBER)
- local_parse_glob(session, p, parsing, seen);
+ local_parse_glob(session, p, parsing);
#else
- local_parse_file(session, p, parsing, seen);
+ local_parse_file(session, p, parsing);
#endif /* HAVE_GLOB */
}
break;
@@ -844,7 +808,6 @@ int ssh_config_parse_file(ssh_session session, const char *filename)
unsigned int count = 0;
FILE *f;
int parsing, rv;
- uint8_t *seen = NULL;
f = fopen(filename, "r");
if (f == NULL) {
@@ -853,23 +816,10 @@ int ssh_config_parse_file(ssh_session session, const char *filename)
SSH_LOG(SSH_LOG_PACKET, "Reading configuration data from %s", filename);
- /* Preserve the seen array among invocations throughout the session */
- if (session->opts.options_seen == NULL) {
- seen = calloc(SOC_END - SOC_UNSUPPORTED, sizeof(uint8_t));
- if (seen == NULL) {
- fclose(f);
- ssh_set_error_oom(session);
- return -1;
- }
- session->opts.options_seen = seen;
- } else {
- seen = session->opts.options_seen;
- }
-
parsing = 1;
while (fgets(line, sizeof(line), f)) {
count++;
- rv = ssh_config_parse_line(session, line, count, &parsing, seen);
+ rv = ssh_config_parse_line(session, line, count, &parsing);
if (rv < 0) {
fclose(f);
return -1;
diff --git a/src/session.c b/src/session.c
index 48103cba..157fe1e7 100644
--- a/src/session.c
+++ b/src/session.c
@@ -283,7 +283,6 @@ void ssh_free(ssh_session session) {
SAFE_FREE(session->opts.gss_server_identity);
SAFE_FREE(session->opts.gss_client_identity);
SAFE_FREE(session->opts.pubkey_accepted_types);
- SAFE_FREE(session->opts.options_seen);
for (i = 0; i < 10; i++) {
if (session->opts.wanted_methods[i]) {
diff --git a/tests/client/torture_client_config.c b/tests/client/torture_client_config.c
index 3d85bdcc..ca81f36d 100644
--- a/tests/client/torture_client_config.c
+++ b/tests/client/torture_client_config.c
@@ -92,8 +92,6 @@ static void torture_client_config_system(void **state)
struct torture_state *s = *state;
int ret = 0;
- assert_true(s->ssh.session->opts.options_seen == NULL);
-
/* The first tests assumes there is system-wide configuration file
* setting Ciphers to some non-default value. We do not have any control
* of that in this test case.
@@ -121,8 +119,6 @@ static void torture_client_config_emulate(void **state)
char *filename = NULL;
int ret = 0;
- assert_true(s->ssh.session->opts.options_seen == NULL);
-
/* The first tests assumes there is system-wide configuration file
* setting Ciphers to some non-default value. We do not have any control
* of that in this test case
@@ -151,8 +147,6 @@ static void torture_client_config_autoparse(void **state)
struct torture_state *s = *state;
int ret = 0;
- assert_true(s->ssh.session->opts.options_seen == NULL);
-
ret = ssh_connect(s->ssh.session);
assert_ssh_return_code(s->ssh.session, ret);
@@ -169,8 +163,6 @@ static void torture_client_config_suppress(void **state)
bool b = false;
int ret = 0;
- assert_true(s->ssh.session->opts.options_seen == NULL);
-
ret = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b);
assert_ssh_return_code(s->ssh.session, ret);
diff --git a/tests/torture.c b/tests/torture.c
index 3500cd50..1585240f 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -1163,6 +1163,10 @@ void torture_write_file(const char *filename, const char *data){
close(fd);
}
+void torture_reset_config(ssh_session session)
+{
+ memset(session->opts.options_seen, 0, sizeof(session->opts.options_seen));
+}
int main(int argc, char **argv) {
struct argument_s arguments;
diff --git a/tests/torture.h b/tests/torture.h
index b47c7cbb..c62bda7c 100644
--- a/tests/torture.h
+++ b/tests/torture.h
@@ -120,6 +120,8 @@ void torture_setup_sshd_server(void **state);
void torture_teardown_socket_dir(void **state);
void torture_teardown_sshd_server(void **state);
+void torture_reset_config(ssh_session session);
+
/*
* This function must be defined in every unit test file.
*/
diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index 095bfa09..733d99a0 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -156,7 +156,6 @@ static int teardown(void **state)
return 0;
}
-
/**
* @brief tests ssh_config_parse_file with Include directives
*/
@@ -300,7 +299,7 @@ static void torture_config_auth_methods(void **state) {
assert_int_equal(session->opts.flags, 0);
/* gradually enable them again */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "gss");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
assert_true(ret == 0);
@@ -355,34 +354,34 @@ static void torture_config_match(void **state)
assert_string_equal(session->opts.host, "all-matched.com");
/* Hostname example does simple hostname matching */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "example");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
assert_true(ret == 0);
assert_string_equal(session->opts.host, "example.com");
/* We can match also both hosts from a comma separated list */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "example1");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
assert_true(ret == 0);
assert_string_equal(session->opts.host, "exampleN");
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "example2");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
assert_true(ret == 0);
assert_string_equal(session->opts.host, "exampleN");
/* We can match by user */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_USER, "guest");
ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG10);
assert_true(ret == 0);
assert_string_equal(session->opts.host, "guest.com");
/* We can combine two options on a single line to match both of them */
- SAFE_FREE(session->opts.options_seen);
+ 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);
@@ -390,7 +389,7 @@ static void torture_config_match(void **state)
assert_string_equal(session->opts.host, "testhost.com");
/* We can also negate conditions */
- SAFE_FREE(session->opts.options_seen);
+ 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);
diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
index d35502a9..1bd8249b 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -462,26 +462,26 @@ static void torture_options_config_host(void **state) {
assert_int_equal(session->opts.port, 42);
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost2");
ssh_options_parse_config(session, "test_config");
assert_int_equal(session->opts.port, 43);
session->opts.port = 0;
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost3");
ssh_options_parse_config(session, "test_config");
assert_int_equal(session->opts.port, 43);
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost4");
ssh_options_parse_config(session, "test_config");
assert_int_equal(session->opts.port, 44);
session->opts.port = 0;
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
ssh_options_set(session, SSH_OPTIONS_HOST, "testhost5");
ssh_options_parse_config(session, "test_config");
assert_int_equal(session->opts.port, 44);
@@ -509,7 +509,7 @@ static void torture_options_config_match(void **state)
assert_ssh_return_code_equal(session, rv, SSH_ERROR);
/* The Match all keyword needs to be the only one (start) */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match all host local\n",
@@ -520,7 +520,7 @@ static void torture_options_config_match(void **state)
assert_ssh_return_code_equal(session, rv, SSH_ERROR);
/* The Match all keyword needs to be the only one (end) */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match host local all\n",
@@ -531,7 +531,7 @@ static void torture_options_config_match(void **state)
assert_ssh_return_code_equal(session, rv, SSH_ERROR);
/* The Match host keyword requires an argument */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match host\n",
@@ -542,7 +542,7 @@ static void torture_options_config_match(void **state)
assert_ssh_return_code_equal(session, rv, SSH_ERROR);
/* The Match user keyword requires an argument */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match user\n",
@@ -553,7 +553,7 @@ static void torture_options_config_match(void **state)
assert_ssh_return_code_equal(session, rv, SSH_ERROR);
/* The Match canonical keyword is ignored */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match canonical\n"
@@ -570,7 +570,7 @@ static void torture_options_config_match(void **state)
session->opts.port = 0;
/* The Match originalhost keyword is ignored */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match originalhost origin\n"
@@ -587,7 +587,7 @@ static void torture_options_config_match(void **state)
session->opts.port = 0;
/* The Match localuser keyword is ignored */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match originalhost origin\n"
@@ -604,7 +604,7 @@ static void torture_options_config_match(void **state)
session->opts.port = 0;
/* The Match exec keyword is ignored */
- SAFE_FREE(session->opts.options_seen);
+ torture_reset_config(session);
config = fopen("test_config", "w");
assert_non_null(config);
fputs("Match exec /bin/true\n"