[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] config: Parse KexAlgorithms, MACs, improve Include


On Tue, 2017-11-07 at 14:28 +0100, Jakub Jelen wrote:
> Hello,
> the attached patch contains a series of patches improving a support
> for
> ssh_config parsing by adding a support for KexAlgorithms and MACs
> options.
> It is also enhancing Include directive parsing to support glob as it
> is
> currently supported in OpenSSH.
> 
> Regards,

After discussion with Andreas, I was pointed to the work-in-progress
branch towards this from Aris [1]. I used this commit as a base (the
first attached commit rebased on current master), updated it to work
properly and enhanced with the work submitted by the previous email.
The changes attached can be also reviewed in the github [2].

With these changes I am passing the whole testsuite against latest
OpenSSH 7.6 server.

[1] https://git.libssh.org/users/aris/libssh.git/log/?h=options
[2] https://github.com/Jakuje/libssh/commits/master

Regards,
-- 
Jakub Jelen
Software Engineer
Security Technologies
Red Hat, Inc.
From 067ecffc997c6661728aca1699f77b2b6c2dada8 Mon Sep 17 00:00:00 2001
From: Aris Adamantiadis <aris@xxxxxxxxxxxx>
Date: Sun, 3 Aug 2014 22:29:49 +0200
Subject: [PATCH 01/21] Add new options

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 include/libssh/libssh.h           |   5 +
 include/libssh/session.h          |   9 ++
 src/auth.c                        |   5 +-
 src/config.c                      | 192 ++++++++++++++++++++++++++++++++++++--
 src/known_hosts.c                 |  41 ++++++--
 src/misc.c                        |  13 ++-
 src/options.c                     |  61 ++++++++++++
 src/session.c                     |   3 +-
 tests/unittests/torture_options.c |  29 ++++++
 9 files changed, 341 insertions(+), 17 deletions(-)

diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index 504a645a..be4b35c2 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -351,6 +351,11 @@ enum ssh_options_e {
   SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS,
   SSH_OPTIONS_HMAC_C_S,
   SSH_OPTIONS_HMAC_S_C,
+  SSH_OPTIONS_PASSWORD_AUTH,
+  SSH_OPTIONS_PUBKEY_AUTH,
+  SSH_OPTIONS_KBDINT_AUTH,
+  SSH_OPTIONS_GSSAPI_AUTH,
+  SSH_OPTIONS_GLOBAL_KNOWNHOSTS
 };
 
 enum {
diff --git a/include/libssh/session.h b/include/libssh/session.h
index 60d78578..e45b8011 100644
--- a/include/libssh/session.h
+++ b/include/libssh/session.h
@@ -79,6 +79,13 @@ enum ssh_pending_call_e {
 /* Don't block at all */
 #define SSH_TIMEOUT_NONBLOCKING 0
 
+/* options flags */
+/* Authentication with *** allowed */
+#define SSH_OPT_FLAG_PASSWORD_AUTH 1
+#define SSH_OPT_FLAG_PUBKEY_AUTH 2
+#define SSH_OPT_FLAG_KBDINT_AUTH 4
+#define SSH_OPT_FLAG_GSSAPI_AUTH 8
+
 /* members that are common to ssh_session and ssh_bind */
 struct ssh_common_struct {
     struct error_struct error;
@@ -182,6 +189,7 @@ struct ssh_session_struct {
         char *bindaddr; /* bind the client to an ip addr */
         char *sshdir;
         char *knownhosts;
+        char *global_knownhosts;
         char *wanted_methods[10];
         char *ProxyCommand;
         char *custombanner;
@@ -196,6 +204,7 @@ struct ssh_session_struct {
         char *gss_server_identity;
         char *gss_client_identity;
         int gss_delegate_creds;
+        int flags;
     } opts;
     /* counters */
     ssh_counter socket_counter;
diff --git a/src/auth.c b/src/auth.c
index 59b6f134..6e3698aa 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -921,7 +921,10 @@ int ssh_userauth_publickey_auto(ssh_session session,
     if (session == NULL) {
         return SSH_AUTH_ERROR;
     }
-
+    if (! (session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH)){
+        session->auth_methods &= ~SSH_AUTH_METHOD_PUBLICKEY;
+        return SSH_AUTH_DENIED;
+    }
     if (session->common.callbacks) {
         auth_fn = session->common.callbacks->auth_function;
         auth_data = session->common.callbacks->userdata;
diff --git a/src/config.c b/src/config.c
index 25d64998..143bbb87 100644
--- a/src/config.c
+++ b/src/config.c
@@ -36,8 +36,14 @@
 #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,
@@ -53,6 +59,17 @@ enum ssh_config_opcode_e {
   SOC_GSSAPICLIENTIDENTITY,
   SOC_GSSAPIDELEGATECREDENTIALS,
   SOC_INCLUDE,
+  SOC_BINDADDRESS,
+  SOC_CONNECTTIMEOUT,
+  SOC_GLOBALKNOWNHOSTSFILE,
+  SOC_LOGLEVEL,
+  SOC_HOSTKEYALGORITHMS,
+  SOC_KEXALGORITHMS,
+  SOC_MAC,
+  SOC_GSSAPIAUTHENTICATION,
+  SOC_KBDINTERACTIVEAUTHENTICATION,
+  SOC_PASSWORDAUTHENTICATION,
+  SOC_PUBKEYAUTHENTICATION,
 
   SOC_END /* Keep this one last in the list */
 };
@@ -64,6 +81,7 @@ struct ssh_config_keyword_table_s {
 
 static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
   { "host", SOC_HOST },
+  { "match", SOC_MATCH },
   { "hostname", SOC_HOSTNAME },
   { "port", SOC_PORT },
   { "user", SOC_USERNAME },
@@ -79,7 +97,76 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
   { "gssapiserveridentity", SOC_GSSAPICLIENTIDENTITY },
   { "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
   { "include", SOC_INCLUDE },
-  { NULL, SOC_UNSUPPORTED }
+  { "bindaddress", SOC_BINDADDRESS},
+  { "connecttimeout", SOC_CONNECTTIMEOUT},
+  { "globalknownhostsfile", SOC_GLOBALKNOWNHOSTSFILE},
+  { "loglevel", SOC_LOGLEVEL},
+  { "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
+  { "kexalgorithms", SOC_KEXALGORITHMS},
+  { "mac", SOC_MAC},
+  { "gssapiauthentication", SOC_GSSAPIAUTHENTICATION},
+  { "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
+  { "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
+  { "pubkeyauthentication", SOC_PUBKEYAUTHENTICATION},
+  { "addressfamily", SOC_UNSUPPORTED},
+  { "batchmode", SOC_UNSUPPORTED},
+  { "canonicaldomains", SOC_UNSUPPORTED},
+  { "canonicalizefallbacklocal", SOC_UNSUPPORTED},
+  { "canonicalizehostname", SOC_UNSUPPORTED},
+  { "canonicalizemaxdots", SOC_UNSUPPORTED},
+  { "canonicalizepermittedcnames", SOC_UNSUPPORTED},
+  { "challengeresponseauthentication", SOC_UNSUPPORTED},
+  { "checkhostip", SOC_UNSUPPORTED},
+  { "cipher", SOC_UNSUPPORTED},
+  { "compressionlevel", SOC_UNSUPPORTED},
+  { "connectionattempts", SOC_UNSUPPORTED},
+  { "enablesshkeysign", SOC_UNSUPPORTED},
+  { "forwardagent", SOC_UNSUPPORTED},
+  { "gssapikeyexchange", SOC_UNSUPPORTED},
+  { "gssapirenewalforcesrekey", SOC_UNSUPPORTED},
+  { "gssapitrustdns", SOC_UNSUPPORTED},
+  { "hashknownhosts", SOC_UNSUPPORTED},
+  { "hostbasedauthentication", SOC_UNSUPPORTED},
+  { "hostkeyalias", SOC_UNSUPPORTED},
+  { "identitiesonly", SOC_UNSUPPORTED},
+  { "ipqos", SOC_UNSUPPORTED},
+  { "kbdinteractivedevices", SOC_UNSUPPORTED},
+  { "nohostauthenticationforlocalhost", SOC_UNSUPPORTED},
+  { "numberofpasswordprompts", SOC_UNSUPPORTED},
+  { "pkcs11provider", SOC_UNSUPPORTED},
+  { "preferredauthentications", SOC_UNSUPPORTED},
+  { "proxyusefdpass", SOC_UNSUPPORTED},
+  { "rekeylimit", SOC_UNSUPPORTED},
+  { "rhostsrsaauthentication", SOC_UNSUPPORTED},
+  { "rsaauthentication", SOC_UNSUPPORTED},
+  { "serveralivecountmax", SOC_UNSUPPORTED},
+  { "serveraliveinterval", SOC_UNSUPPORTED},
+  { "tcpkeepalive", SOC_UNSUPPORTED},
+  { "useprivilegedport", SOC_UNSUPPORTED},
+  { "verifyhostkeydns", SOC_UNSUPPORTED},
+  { "visualhostkey", SOC_UNSUPPORTED},
+  { "clearallforwardings", SOC_NA},
+  { "controlmaster", SOC_NA},
+  { "controlpersist", SOC_NA},
+  { "controlpath", SOC_NA},
+  { "dynamicforward", SOC_NA},
+  { "escapechar", SOC_NA},
+  { "exitonforwardfailure", SOC_NA},
+  { "forwardx11", SOC_NA},
+  { "forwardx11timeout", SOC_NA},
+  { "forwardx11trusted", SOC_NA},
+  { "gatewayports", SOC_NA},
+  { "ignoreunknown", SOC_NA},
+  { "localcommand", SOC_NA},
+  { "localforward", SOC_NA},
+  { "permitlocalcommand", SOC_NA},
+  { "remoteforward", SOC_NA},
+  { "requesttty", SOC_NA},
+  { "sendenv", SOC_NA},
+  { "tunnel", SOC_NA},
+  { "tunneldevice", SOC_NA},
+  { "xauthlocation", SOC_NA},
+  { NULL, SOC_UNKNOWN }
 };
 
 static int ssh_config_parse_line(ssh_session session, const char *line,
@@ -94,7 +181,7 @@ static enum ssh_config_opcode_e ssh_config_get_opcode(char *keyword) {
     }
   }
 
-  return SOC_UNSUPPORTED;
+  return SOC_UNKNOWN;
 }
 
 static char *ssh_config_get_cmd(char **str) {
@@ -297,12 +384,10 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
       }
       break;
     case SOC_PORT:
-      if (session->opts.port == 0) {
-          p = ssh_config_get_str_tok(&s, NULL);
-          if (p && *parsing) {
-              ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
-          }
-      }
+        p = ssh_config_get_str_tok(&s, NULL);
+        if (p && *parsing) {
+            ssh_options_set(session, SSH_OPTIONS_PORT_STR, p);
+        }
       break;
     case SOC_USERNAME:
       if (session->opts.username == NULL) {
@@ -408,10 +493,101 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
         ssh_options_set(session, SSH_OPTIONS_GSSAPI_DELEGATE_CREDENTIALS, &i);
       }
       break;
+    case SOC_BINDADDRESS:
+      p = ssh_config_get_str_tok(&s, NULL);
+      if (p && *parsing) {
+          ssh_options_set(session, SSH_OPTIONS_BINDADDR, p);
+      }
+      break;
+    case SOC_CONNECTTIMEOUT:
+      i = ssh_config_get_int(&s, 0);
+      if (i >= 0 && *parsing){
+        long t = i;
+        ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &t);
+      }
+      break;
+    case SOC_GLOBALKNOWNHOSTSFILE:
+        p = ssh_config_get_str_tok(&s, NULL);
+        if (p && *parsing){
+            ssh_options_set(session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, p);
+        }
+        break;
+    case SOC_LOGLEVEL:
+        p = ssh_config_get_str_tok(&s, NULL);
+        if (p && *parsing){
+            if (strcasecmp(p, "quiet") == 0){
+                ssh_set_log_level(SSH_LOG_NONE);
+            } else if (strcasecmp(p, "fatal") == 0 ||
+                    strcasecmp(p, "error")== 0 ||
+                    strcasecmp(p, "info") == 0) {
+                ssh_set_log_level(SSH_LOG_WARN);
+            } else if (strcasecmp(p, "verbose") == 0) {
+                ssh_set_log_level(SSH_LOG_INFO);
+            } else if (strcasecmp(p, "DEBUG") == 0 ||
+                    strcasecmp(p, "DEBUG1") == 0){
+                ssh_set_log_level(SSH_LOG_DEBUG);
+            } else if (strcasecmp(p, "DEBUG2") == 0 ||
+                    strcasecmp(p, "DEBUG3") == 0){
+                ssh_set_log_level(SSH_LOG_TRACE);
+            }
+        }
+        break;
+    case SOC_HOSTKEYALGORITHMS:
+        p = ssh_config_get_str_tok(&s, NULL);
+        if (p && *parsing){
+            ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, p);
+        }
+        break;
+    case SOC_KEXALGORITHMS:
+        p = ssh_config_get_str_tok(&s, NULL);
+        if (p && *parsing){
+            ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
+        }
+        break;
+    case SOC_MAC:
+        p = ssh_config_get_str_tok(&s, NULL);
+        if (p && *parsing){
+            ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, p);
+            ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, p);
+        }
+        break;
+    case SOC_GSSAPIAUTHENTICATION:
+    case SOC_KBDINTERACTIVEAUTHENTICATION:
+    case SOC_PASSWORDAUTHENTICATION:
+    case SOC_PUBKEYAUTHENTICATION:
+        i = ssh_config_get_yesno(&s, 0);
+        if (i>=0 && *parsing){
+            switch(opcode){
+            case SOC_GSSAPIAUTHENTICATION:
+                ssh_options_set(session, SSH_OPTIONS_GSSAPI_AUTH, &i);
+                break;
+            case SOC_KBDINTERACTIVEAUTHENTICATION:
+                ssh_options_set(session, SSH_OPTIONS_KBDINT_AUTH, &i);
+                break;
+            case SOC_PASSWORDAUTHENTICATION:
+                ssh_options_set(session, SSH_OPTIONS_PASSWORD_AUTH, &i);
+                break;
+            case SOC_PUBKEYAUTHENTICATION:
+                ssh_options_set(session, SSH_OPTIONS_PUBKEY_AUTH, &i);
+                break;
+            /* make gcc happy */
+            default:
+                break;
+            }
+        }
+        break;
+    case SOC_NA:
+      SSH_LOG(SSH_LOG_INFO, "Unapplicable option: %s, line: %d\n",
+              keyword, count);
+      break;
     case SOC_UNSUPPORTED:
       SSH_LOG(SSH_LOG_RARE, "Unsupported option: %s, line: %d",
               keyword, count);
       break;
+    case SOC_UNKNOWN:
+      SSH_LOG(SSH_LOG_WARN, "Unknown option: %s, line: %d\n",
+              keyword, count);
+      break;
     default:
       ssh_set_error(session, SSH_FATAL, "ERROR - unimplemented opcode: %d",
               opcode);
diff --git a/src/known_hosts.c b/src/known_hosts.c
index 2f66cc27..1c4db716 100644
--- a/src/known_hosts.c
+++ b/src/known_hosts.c
@@ -410,6 +410,8 @@ int ssh_is_server_known(ssh_session session) {
   char *hostport;
   const char *type;
   int match;
+  int i=0;
+  char * files[3];
   int ret = SSH_SERVER_NOT_KNOWN;
 
   if (session->opts.knownhosts == NULL) {
@@ -444,14 +446,27 @@ int ssh_is_server_known(ssh_session session) {
     return SSH_SERVER_ERROR;
   }
 
+  /* set the list of known hosts */
+  i = 0;
+  if (session->opts.global_knownhosts != NULL){
+      files[i++]=session->opts.global_knownhosts;
+  }
+  files[i++] = session->opts.knownhosts;
+  files[i] = NULL;
+  i = 0;
+
   do {
     tokens = ssh_get_knownhost_line(&file,
-                                    session->opts.knownhosts,
+                                    files[i],
                                     &type);
 
-    /* End of file, return the current state */
+    /* End of file, return the current state or use next file */
     if (tokens == NULL) {
-      break;
+      ++i;
+      if(files[i] == NULL)
+          break;
+      else
+          continue;
     }
     match = match_hashed_host(host, tokens[0]);
     if (match == 0){
@@ -694,7 +709,8 @@ char **ssh_knownhosts_algorithms(ssh_session session) {
   const char *type;
   int match;
   char **array;
-  int i=0, j;
+  char *files[3];
+  int i=0, j, k;
 
   if (session->opts.knownhosts == NULL) {
     if (ssh_options_apply(session) < 0) {
@@ -720,13 +736,26 @@ char **ssh_knownhosts_algorithms(ssh_session session) {
     return NULL;
   }
 
+  /* set the list of known hosts */
+  i = 0;
+  if (session->opts.global_knownhosts != NULL){
+      files[i++]=session->opts.global_knownhosts;
+  }
+  files[i++] = session->opts.knownhosts;
+  files[i] = NULL;
+  k = 0;
+
   do {
     tokens = ssh_get_knownhost_line(&file,
-    		session->opts.knownhosts, &type);
+    		files[k], &type);
 
     /* End of file, return the current state */
     if (tokens == NULL) {
-      break;
+      ++k;
+      if(files[k] == NULL)
+          break;
+      else
+          continue;
     }
     match = match_hashed_host(host, tokens[0]);
     if (match == 0){
diff --git a/src/misc.c b/src/misc.c
index 5b260b15..fad33294 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -681,6 +681,17 @@ char *ssh_path_expand_tilde(const char *d) {
     return r;
 }
 
+/** @internal
+ * @brief expands a string in function of session options
+ * @param[in] s Format string to expand. Known parameters:
+ *              %d SSH configuration directory (~/.ssh)
+ *              %h target host name
+ *              %u local username
+ *              %l local hostname
+ *              %r remote username
+ *              %p remote port
+ * @returns Expanded string.
+ */
 char *ssh_path_expand_escape(ssh_session session, const char *s) {
     char host[NI_MAXHOST];
     char buf[MAX_BUF_SIZE];
@@ -971,7 +982,7 @@ int ssh_timeout_elapsed(struct ssh_timestamp *ts, int timeout) {
                   * -2 means user-defined timeout as available in
                   * session->timeout, session->timeout_usec.
                   */
-            fprintf(stderr, "ssh_timeout_elapsed called with -2. this needs to "
+            SSH_LOG(SSH_LOG_WARN, "ssh_timeout_elapsed called with -2. this needs to "
                             "be fixed. please set a breakpoint on %s:%d and "
                             "fix the caller\n", __FILE__, __LINE__);
             return 0;
diff --git a/src/options.c b/src/options.c
index 9346b6d1..0bc15497 100644
--- a/src/options.c
+++ b/src/options.c
@@ -374,6 +374,28 @@ int ssh_options_set_algo(ssh_session session,
  *                Set it to specify that GSSAPI should delegate credentials
  *                to the server (int, 0 = false).
  *
+ *              - SSH_OPTIONS_PASSWORD_AUTH
+ *                Set it if password authentication should be used
+ *                in ssh_userauth_auto_pubkey(). (int, 0=false).
+ *                Currently without effect (ssh_userauth_auto_pubkey doesn't use
+ *                password authentication).
+ *
+ *              - SSH_OPTIONS_PUBKEY_AUTH
+ *                Set it if pubkey authentication should be used
+ *                in ssh_userauth_auto_pubkey(). (int, 0=false).
+ *
+ *              - SSH_OPTIONS_KBDINT_AUTH
+ *                Set it if keyboard-interactive authentication should be used
+ *                in ssh_userauth_auto_pubkey(). (int, 0=false).
+ *                Currently without effect (ssh_userauth_auto_pubkey doesn't use
+ *                keyboard-interactive authentication).
+ *
+ *              - SSH_OPTIONS_GSSAPI_AUTH
+ *                Set it if gssapi authentication should be used
+ *                in ssh_userauth_auto_pubkey(). (int, 0=false).
+ *                Currently without effect (ssh_userauth_auto_pubkey doesn't use
+ *                gssapi authentication).
+ *
  * @param  value The value to set. This is a generic pointer and the
  *               datatype which is used should be set according to the
  *               type set.
@@ -385,6 +407,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
     const char *v;
     char *p, *q;
     long int i;
+    unsigned int u;
     int rc;
 
     if (session == NULL) {
@@ -574,6 +597,20 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
                 }
             }
             break;
+        case SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
+            v = value;
+            SAFE_FREE(session->opts.global_knownhosts);
+            if (v == NULL || v[0] == '\0') {
+                ssh_set_error_invalid(session);
+                return -1;
+            } else {
+                session->opts.global_knownhosts = strdup(v);
+                if (session->opts.global_knownhosts == NULL) {
+                    ssh_set_error_oom(session);
+                    return -1;
+                }
+            }
+            break;
         case SSH_OPTIONS_TIMEOUT:
             if (value == NULL) {
                 ssh_set_error_invalid(session);
@@ -858,6 +895,30 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
                 session->opts.gss_delegate_creds = (x & 0xff);
             }
             break;
+        case SSH_OPTIONS_PASSWORD_AUTH:
+        case SSH_OPTIONS_PUBKEY_AUTH:
+        case SSH_OPTIONS_KBDINT_AUTH:
+        case SSH_OPTIONS_GSSAPI_AUTH:
+            u = 0;
+            if (value == NULL) {
+                ssh_set_error_invalid(session);
+                return -1;
+            } else {
+                int x = *(int *)value;
+                u = type == SSH_OPTIONS_PASSWORD_AUTH ?
+                    SSH_OPT_FLAG_PASSWORD_AUTH:
+                    type == SSH_OPTIONS_PUBKEY_AUTH ?
+                        SSH_OPT_FLAG_PUBKEY_AUTH:
+                        type == SSH_OPTIONS_KBDINT_AUTH ?
+                            SSH_OPT_FLAG_KBDINT_AUTH:
+                            SSH_OPT_FLAG_GSSAPI_AUTH;
+                if (x != 0){
+                    session->opts.flags |= u;
+                } else {
+                    session->opts.flags &= ~u;
+                }
+            }
+            break;
 
         default:
             ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
diff --git a/src/session.c b/src/session.c
index 60c72b92..bb01f169 100644
--- a/src/session.c
+++ b/src/session.c
@@ -112,7 +112,8 @@ ssh_session ssh_new(void) {
 #else
     session->opts.ssh1 = 0;
 #endif
-
+    session->opts.flags = SSH_OPT_FLAG_PASSWORD_AUTH | SSH_OPT_FLAG_PUBKEY_AUTH |
+            SSH_OPT_FLAG_KBDINT_AUTH | SSH_OPT_FLAG_GSSAPI_AUTH;
     session->opts.identity = ssh_list_new();
     if (session->opts.identity == NULL) {
       goto err;
diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
index f3197b8f..7429095a 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -239,6 +239,34 @@ static void torture_options_proxycommand(void **state) {
     assert_null(session->opts.ProxyCommand);
 }
 
+static void torture_options_config_host(void **state) {
+    ssh_session session = *state;
+    FILE *config;
+    int rc;
+
+    /* create a new config file */
+    config = fopen("test_config", "w");
+    assert_non_null(config);
+    fputs("Host testhost1\nPort 42\nHost testhost2,testhost3\nPort 43\n", config);
+    fclose(config);
+
+    ssh_options_set(session, SSH_OPTIONS_HOST, "testhost1");
+    ssh_options_parse_config(session, "test_config");
+
+    assert_int_equal(session->opts.port, 42);
+
+    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;
+
+    ssh_options_set(session, SSH_OPTIONS_HOST, "testhost3");
+    ssh_options_parse_config(session, "test_config");
+    assert_int_equal(session->opts.port, 43);
+
+}
+
 
 #ifdef WITH_SERVER
 /* sshbind options */
@@ -304,6 +332,7 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_options_proxycommand, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_set_ciphers, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_set_macs, setup, teardown),
+        cmocka_unit_test_setup_teardown(torture_options_config_host, setup, teardown)
     };
 
 #ifdef WITH_SERVER
-- 
2.13.6


From 4a667ad8ed23bbf1befa85b237d028abccbee058 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 13 Nov 2017 11:51:52 +0100
Subject: [PATCH 02/21] options: Document SSH_OPTIONS_GLOBAL_KNOWNHOSTS and set
 default value

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 src/options.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/src/options.c b/src/options.c
index 0bc15497..54e768e5 100644
--- a/src/options.c
+++ b/src/options.c
@@ -238,6 +238,16 @@ int ssh_options_set_algo(ssh_session session,
  *                are genuine. It may include "%s" which will be
  *                replaced by the user home directory.
  *
+ *              - SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
+ *                Set the global known hosts file name (const char *,format string).\n
+ *                \n
+ *                If the value is NULL, the directory is set to the
+ *                default global known hosts file, normally
+ *                /etc/ssh/ssh_known_hosts.\n
+ *                \n
+ *                The known hosts file is used to certify remote hosts
+ *                are genuine.
+ *
  *              - SSH_OPTIONS_IDENTITY:
  *                Set the identity file name (const char *,format string).\n
  *                \n
@@ -600,7 +610,14 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
         case SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
             v = value;
             SAFE_FREE(session->opts.global_knownhosts);
-            if (v == NULL || v[0] == '\0') {
+            if (v == NULL) {
+                session->opts.global_knownhosts =
+                    strdup("/etc/ssh/ssh_known_hosts");
+                if (session->opts.global_knownhosts == NULL) {
+                    ssh_set_error_oom(session);
+                    return -1;
+                }
+            } else if (v[0] == '\0') {
                 ssh_set_error_invalid(session);
                 return -1;
             } else {
-- 
2.13.6


From ba7c5699300c5ce40905e3209b83183c81626cac Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 13 Nov 2017 11:28:45 +0100
Subject: [PATCH 03/21] config: Add configuration options from current OpenSSH
 7.5 (and fix typos)

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 src/config.c | 30 +++++++++++++++++-------------
 1 file changed, 17 insertions(+), 13 deletions(-)

diff --git a/src/config.c b/src/config.c
index 143bbb87..e8778bb4 100644
--- a/src/config.c
+++ b/src/config.c
@@ -60,7 +60,6 @@ enum ssh_config_opcode_e {
   SOC_GSSAPIDELEGATECREDENTIALS,
   SOC_INCLUDE,
   SOC_BINDADDRESS,
-  SOC_CONNECTTIMEOUT,
   SOC_GLOBALKNOWNHOSTSFILE,
   SOC_LOGLEVEL,
   SOC_HOSTKEYALGORITHMS,
@@ -94,11 +93,10 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
   { "userknownhostsfile", SOC_KNOWNHOSTS },
   { "proxycommand", SOC_PROXYCOMMAND },
   { "gssapiserveridentity", SOC_GSSAPISERVERIDENTITY },
-  { "gssapiserveridentity", SOC_GSSAPICLIENTIDENTITY },
+  { "gssapiclientidentity", SOC_GSSAPICLIENTIDENTITY },
   { "gssapidelegatecredentials", SOC_GSSAPIDELEGATECREDENTIALS },
   { "include", SOC_INCLUDE },
   { "bindaddress", SOC_BINDADDRESS},
-  { "connecttimeout", SOC_CONNECTTIMEOUT},
   { "globalknownhostsfile", SOC_GLOBALKNOWNHOSTSFILE},
   { "loglevel", SOC_LOGLEVEL},
   { "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
@@ -108,6 +106,7 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
   { "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
   { "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
   { "pubkeyauthentication", SOC_PUBKEYAUTHENTICATION},
+  { "addkeystoagent", SOC_UNSUPPORTED},
   { "addressfamily", SOC_UNSUPPORTED},
   { "batchmode", SOC_UNSUPPORTED},
   { "canonicaldomains", SOC_UNSUPPORTED},
@@ -115,33 +114,45 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
   { "canonicalizehostname", SOC_UNSUPPORTED},
   { "canonicalizemaxdots", SOC_UNSUPPORTED},
   { "canonicalizepermittedcnames", SOC_UNSUPPORTED},
+  { "certificatefile", SOC_UNSUPPORTED},
   { "challengeresponseauthentication", SOC_UNSUPPORTED},
   { "checkhostip", SOC_UNSUPPORTED},
-  { "cipher", SOC_UNSUPPORTED},
-  { "compressionlevel", SOC_UNSUPPORTED},
+  { "cipher", SOC_UNSUPPORTED}, /* SSHv1 */
+  { "compressionlevel", SOC_UNSUPPORTED}, /* SSHv1 */
   { "connectionattempts", SOC_UNSUPPORTED},
   { "enablesshkeysign", SOC_UNSUPPORTED},
+  { "fingerprinthash", SOC_UNSUPPORTED},
   { "forwardagent", SOC_UNSUPPORTED},
   { "gssapikeyexchange", SOC_UNSUPPORTED},
   { "gssapirenewalforcesrekey", SOC_UNSUPPORTED},
   { "gssapitrustdns", SOC_UNSUPPORTED},
   { "hashknownhosts", SOC_UNSUPPORTED},
   { "hostbasedauthentication", SOC_UNSUPPORTED},
+  { "hostbasedkeytypes", SOC_UNSUPPORTED},
   { "hostkeyalias", SOC_UNSUPPORTED},
   { "identitiesonly", SOC_UNSUPPORTED},
+  { "identityagent", SOC_UNSUPPORTED},
   { "ipqos", SOC_UNSUPPORTED},
   { "kbdinteractivedevices", SOC_UNSUPPORTED},
   { "nohostauthenticationforlocalhost", SOC_UNSUPPORTED},
   { "numberofpasswordprompts", SOC_UNSUPPORTED},
   { "pkcs11provider", SOC_UNSUPPORTED},
   { "preferredauthentications", SOC_UNSUPPORTED},
+  { "proxyjump", SOC_UNSUPPORTED},
   { "proxyusefdpass", SOC_UNSUPPORTED},
+  { "pubkeyacceptedtypes", SOC_UNSUPPORTED},
   { "rekeylimit", SOC_UNSUPPORTED},
+  { "remotecommand", SOC_UNSUPPORTED},
+  { "revokedhostkeys", SOC_UNSUPPORTED},
   { "rhostsrsaauthentication", SOC_UNSUPPORTED},
-  { "rsaauthentication", SOC_UNSUPPORTED},
+  { "rsaauthentication", SOC_UNSUPPORTED}, /* SSHv1 */
   { "serveralivecountmax", SOC_UNSUPPORTED},
   { "serveraliveinterval", SOC_UNSUPPORTED},
+  { "streamlocalbindmask", SOC_UNSUPPORTED},
+  { "streamlocalbindunlink", SOC_UNSUPPORTED},
+  { "syslogfacility", SOC_UNSUPPORTED},
   { "tcpkeepalive", SOC_UNSUPPORTED},
+  { "updatehostkeys", SOC_UNSUPPORTED},
   { "useprivilegedport", SOC_UNSUPPORTED},
   { "verifyhostkeydns", SOC_UNSUPPORTED},
   { "visualhostkey", SOC_UNSUPPORTED},
@@ -499,13 +510,6 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
           ssh_options_set(session, SSH_OPTIONS_BINDADDR, p);
       }
       break;
-    case SOC_CONNECTTIMEOUT:
-      i = ssh_config_get_int(&s, 0);
-      if (i >= 0 && *parsing){
-        long t = i;
-        ssh_options_set(session, SSH_OPTIONS_TIMEOUT, &t);
-      }
-      break;
     case SOC_GLOBALKNOWNHOSTSFILE:
         p = ssh_config_get_str_tok(&s, NULL);
         if (p && *parsing){
-- 
2.13.6


From fa3c54824c00276319c2adae4eaf4c7327913fb4 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 23 Nov 2017 14:33:28 +0100
Subject: [PATCH 04/21] config: Remove MAC option (SSHv1)

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 src/config.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/src/config.c b/src/config.c
index e8778bb4..d7bc041e 100644
--- a/src/config.c
+++ b/src/config.c
@@ -64,7 +64,6 @@ enum ssh_config_opcode_e {
   SOC_LOGLEVEL,
   SOC_HOSTKEYALGORITHMS,
   SOC_KEXALGORITHMS,
-  SOC_MAC,
   SOC_GSSAPIAUTHENTICATION,
   SOC_KBDINTERACTIVEAUTHENTICATION,
   SOC_PASSWORDAUTHENTICATION,
@@ -101,7 +100,7 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
   { "loglevel", SOC_LOGLEVEL},
   { "hostkeyalgorithms", SOC_HOSTKEYALGORITHMS},
   { "kexalgorithms", SOC_KEXALGORITHMS},
-  { "mac", SOC_MAC},
+  { "mac", SOC_UNSUPPORTED}, /* SSHv1 */
   { "gssapiauthentication", SOC_GSSAPIAUTHENTICATION},
   { "kbdinteractiveauthentication", SOC_KBDINTERACTIVEAUTHENTICATION},
   { "passwordauthentication", SOC_PASSWORDAUTHENTICATION},
@@ -548,13 +547,6 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
             ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, p);
         }
         break;
-    case SOC_MAC:
-        p = ssh_config_get_str_tok(&s, NULL);
-        if (p && *parsing){
-            ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, p);
-            ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, p);
-        }
-        break;
     case SOC_GSSAPIAUTHENTICATION:
     case SOC_KBDINTERACTIVEAUTHENTICATION:
     case SOC_PASSWORDAUTHENTICATION:
-- 
2.13.6


From 859c8bf86763a31b84c193b7e49a1078541d10c7 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 13 Nov 2017 13:51:45 +0100
Subject: [PATCH 05/21] options: Typo. The expand character is %d

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 src/options.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/options.c b/src/options.c
index 54e768e5..3fd0ae35 100644
--- a/src/options.c
+++ b/src/options.c
@@ -235,7 +235,7 @@ int ssh_options_set_algo(ssh_session session,
  *                ~/.ssh/known_hosts.\n
  *                \n
  *                The known hosts file is used to certify remote hosts
- *                are genuine. It may include "%s" which will be
+ *                are genuine. It may include "%d" which will be
  *                replaced by the user home directory.
  *
  *              - SSH_OPTIONS_GLOBAL_KNOWNHOSTS:
-- 
2.13.6


From df489d3551b435df96c31cb07336193cb0c87f62 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 20 Nov 2017 14:46:19 +0100
Subject: [PATCH 06/21] config: Set global log level from configuration file

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 src/config.c | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/config.c b/src/config.c
index d7bc041e..6668e25a 100644
--- a/src/config.c
+++ b/src/config.c
@@ -518,20 +518,24 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
     case SOC_LOGLEVEL:
         p = ssh_config_get_str_tok(&s, NULL);
         if (p && *parsing){
+            int value = -1;
             if (strcasecmp(p, "quiet") == 0){
-                ssh_set_log_level(SSH_LOG_NONE);
+                value = SSH_LOG_NONE;
             } else if (strcasecmp(p, "fatal") == 0 ||
                     strcasecmp(p, "error")== 0 ||
                     strcasecmp(p, "info") == 0) {
-                ssh_set_log_level(SSH_LOG_WARN);
+                value = SSH_LOG_WARN;
             } else if (strcasecmp(p, "verbose") == 0) {
-                ssh_set_log_level(SSH_LOG_INFO);
+                value = SSH_LOG_INFO;
             } else if (strcasecmp(p, "DEBUG") == 0 ||
                     strcasecmp(p, "DEBUG1") == 0){
-                ssh_set_log_level(SSH_LOG_DEBUG);
+                value = SSH_LOG_DEBUG;
             } else if (strcasecmp(p, "DEBUG2") == 0 ||
                     strcasecmp(p, "DEBUG3") == 0){
-                ssh_set_log_level(SSH_LOG_TRACE);
+                value = SSH_LOG_TRACE;
+            }
+            if (value != -1) {
+                ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &value);
             }
         }
         break;
-- 
2.13.6


From a3a40a823f8d90fd2fe8115d3f94fc473e0643e5 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Tue, 21 Nov 2017 16:08:45 +0100
Subject: [PATCH 07/21] known_hosts: Avoid segfault

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 src/known_hosts.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/known_hosts.c b/src/known_hosts.c
index 1c4db716..0a38fe63 100644
--- a/src/known_hosts.c
+++ b/src/known_hosts.c
@@ -737,13 +737,13 @@ char **ssh_knownhosts_algorithms(ssh_session session) {
   }
 
   /* set the list of known hosts */
-  i = 0;
   if (session->opts.global_knownhosts != NULL){
       files[i++]=session->opts.global_knownhosts;
   }
   files[i++] = session->opts.knownhosts;
   files[i] = NULL;
   k = 0;
+  i = 0;
 
   do {
     tokens = ssh_get_knownhost_line(&file,
-- 
2.13.6


From 698fd5aacfa5708b5787a92c8555f1e2896c2a0e Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 13 Nov 2017 10:45:48 +0100
Subject: [PATCH 08/21] tests/options: avoid unused variable

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_options.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
index 7429095a..36d7734e 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -242,7 +242,6 @@ static void torture_options_proxycommand(void **state) {
 static void torture_options_config_host(void **state) {
     ssh_session session = *state;
     FILE *config;
-    int rc;
 
     /* create a new config file */
     config = fopen("test_config", "w");
-- 
2.13.6


From 9e1c51e2767d146ef78dd47ca97fb842e70dfcca Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 23 Oct 2017 14:53:55 +0200
Subject: [PATCH 09/21] tests/options: Verify Key exchange algorithms are set
 properly

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_options.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
index 36d7734e..8d891c16 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -59,6 +59,25 @@ static void torture_options_set_ciphers(void **state) {
     assert_false(rc == 0);
 }
 
+static void torture_options_set_key_exchange(void **state) {
+    ssh_session session = *state;
+    int rc;
+
+    /* Test known kexes */
+    rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, "curve25519-sha256@xxxxxxxxxx,ecdh-sha2-nistp256,diffie-hellman-group14-sha1");
+    assert_true(rc == 0);
+    assert_string_equal(session->opts.wanted_methods[SSH_KEX], "curve25519-sha256@xxxxxxxxxx,ecdh-sha2-nistp256,diffie-hellman-group14-sha1");
+
+    /* Test one unknown kex */
+    rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, "curve25519-sha256@xxxxxxxxxx,unknown-crap@xxxxxxxxxxx,diffie-hellman-group14-sha1");
+    assert_true(rc == 0);
+    assert_string_equal(session->opts.wanted_methods[SSH_KEX], "curve25519-sha256@xxxxxxxxxx,diffie-hellman-group14-sha1");
+
+    /* Test all unknown kexes */
+    rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, "unknown-crap@xxxxxxxxxxx,more-crap@xxxxxxxxxxx");
+    assert_false(rc == 0);
+}
+
 static void torture_options_set_macs(void **state) {
     ssh_session session = *state;
     int rc;
@@ -330,6 +349,7 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_options_get_identity, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_proxycommand, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_set_ciphers, setup, teardown),
+        cmocka_unit_test_setup_teardown(torture_options_set_key_exchange, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_set_macs, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_config_host, setup, teardown)
     };
-- 
2.13.6


From 6ad643f7928f5fbbf69966c8cbe77b9eb5738e66 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 23 Oct 2017 15:06:12 +0200
Subject: [PATCH 10/21] tests/config: KexAlgorithms parsing in ssh_config

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_config.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index 0b17a7ab..ec0dde53 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -4,6 +4,7 @@
 
 #include "torture.h"
 #include "libssh/options.h"
+#include "libssh/session.h"
 
 #define LIBSSH_TESTCONFIG1 "libssh_testconfig1.tmp"
 #define LIBSSH_TESTCONFIG2 "libssh_testconfig2.tmp"
@@ -13,6 +14,7 @@
 #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-group14-sha1"
 
 static int setup_config_files(void **state)
 {
@@ -29,7 +31,8 @@ static int setup_config_files(void **state)
                        "Include "LIBSSH_TESTCONFIG3"\n"
                        "ProxyCommand "PROXYCMD"\n\n");
     torture_write_file(LIBSSH_TESTCONFIG3,
-                       "\n\nIdentityFile "ID_FILE"\n");
+                       "\n\nIdentityFile "ID_FILE"\n"
+                       "\n\nKexAlgorithms "KEXALGORITHMS"\n");
 
     /* Multiple Port settings -> parsing returns early. */
     torture_write_file(LIBSSH_TESTCONFIG4,
@@ -85,6 +88,7 @@ static void torture_config_from_file(void **state) {
     assert_string_equal(v, USERNAME);
     ssh_string_free_char(v);
 
+    assert_string_equal(session->opts.wanted_methods[SSH_KEX], KEXALGORITHMS);
 }
 
 /**
-- 
2.13.6


From 235f8bc726ae1adb0e2999b42a8b4699fe2f37eb Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 23 Oct 2017 16:33:28 +0200
Subject: [PATCH 11/21] config: support for MACs

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 src/config.c                      | 9 +++++++++
 tests/unittests/torture_config.c  | 7 ++++++-
 tests/unittests/torture_options.c | 5 +++++
 3 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/src/config.c b/src/config.c
index 6668e25a..77248fdd 100644
--- a/src/config.c
+++ b/src/config.c
@@ -49,6 +49,7 @@ enum ssh_config_opcode_e {
   SOC_USERNAME,
   SOC_IDENTITY,
   SOC_CIPHERS,
+  SOC_MACS,
   SOC_COMPRESSION,
   SOC_TIMEOUT,
   SOC_PROTOCOL,
@@ -85,6 +86,7 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
   { "user", SOC_USERNAME },
   { "identityfile", SOC_IDENTITY },
   { "ciphers", SOC_CIPHERS },
+  { "macs", SOC_MACS },
   { "compression", SOC_COMPRESSION },
   { "connecttimeout", SOC_TIMEOUT },
   { "protocol", SOC_PROTOCOL },
@@ -420,6 +422,13 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
         ssh_options_set(session, SSH_OPTIONS_CIPHERS_S_C, p);
       }
       break;
+    case SOC_MACS:
+      p = ssh_config_get_str_tok(&s, NULL);
+      if (p && *parsing) {
+        ssh_options_set(session, SSH_OPTIONS_HMAC_C_S, p);
+        ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, p);
+      }
+      break;
     case SOC_COMPRESSION:
       i = ssh_config_get_yesno(&s, -1);
       if (i >= 0 && *parsing) {
diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index ec0dde53..a0b40239 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -15,6 +15,7 @@
 #define PROXYCMD "ssh -q -W %h:%p gateway.example.com"
 #define ID_FILE "/etc/xxx"
 #define KEXALGORITHMS "ecdh-sha2-nistp521,diffie-hellman-group14-sha1"
+#define MACS "hmac-sha1,hmac-sha2-256"
 
 static int setup_config_files(void **state)
 {
@@ -32,7 +33,8 @@ static int setup_config_files(void **state)
                        "ProxyCommand "PROXYCMD"\n\n");
     torture_write_file(LIBSSH_TESTCONFIG3,
                        "\n\nIdentityFile "ID_FILE"\n"
-                       "\n\nKexAlgorithms "KEXALGORITHMS"\n");
+                       "\n\nKexAlgorithms "KEXALGORITHMS"\n"
+                       "\n\nMACs "MACS"\n");
 
     /* Multiple Port settings -> parsing returns early. */
     torture_write_file(LIBSSH_TESTCONFIG4,
@@ -89,6 +91,9 @@ static void torture_config_from_file(void **state) {
     ssh_string_free_char(v);
 
     assert_string_equal(session->opts.wanted_methods[SSH_KEX], KEXALGORITHMS);
+
+    assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], MACS);
+    assert_string_equal(session->opts.wanted_methods[SSH_MAC_S_C], MACS);
 }
 
 /**
diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
index 8d891c16..678d4a4c 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -87,6 +87,11 @@ static void torture_options_set_macs(void **state) {
     assert_true(rc == 0);
     assert_string_equal(session->opts.wanted_methods[SSH_MAC_S_C], "hmac-sha1");
 
+    /* Test multiple known MACs */
+    rc = ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, "hmac-sha1,hmac-sha2-256");
+    assert_true(rc == 0);
+    assert_string_equal(session->opts.wanted_methods[SSH_MAC_S_C], "hmac-sha1,hmac-sha2-256");
+
     /* Test unknown MACs */
     rc = ssh_options_set(session, SSH_OPTIONS_HMAC_S_C, "unknown-crap@xxxxxxxxxxx,hmac-sha1,unknown@xxxxxxxxxxx");
     assert_true(rc == 0);
-- 
2.13.6


From dc7ade1bf2e4fa1824a05009d80814c76c16f481 Mon Sep 17 00:00:00 2001
From: NoName115 <robert.kolcun@xxxxxxxxx>
Date: Wed, 25 Oct 2017 14:20:52 +0200
Subject: [PATCH 12/21] config: glob support for include with test

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 src/config.c                     | 28 +++++++++++++++++++++++++++-
 tests/unittests/torture_config.c | 40 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/src/config.c b/src/config.c
index 77248fdd..9aa339ef 100644
--- a/src/config.c
+++ b/src/config.c
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <glob.h>
 
 #include "libssh/priv.h"
 #include "libssh/session.h"
@@ -316,6 +317,31 @@ static void local_parse_file(ssh_session session, const char *filename, int *par
   return;
 }
 
+static void local_parse_glob(ssh_session session, const char *fileglob, int *parsing, int seen[]) {
+  glob_t globbuf;
+  int rt;
+  u_int i;
+
+  memset(&globbuf, 0, sizeof(globbuf));
+  rt = glob(fileglob, GLOB_TILDE, NULL, &globbuf);
+  if (rt == GLOB_NOMATCH) {
+    globfree(&globbuf);
+    return;
+  }
+  else if (rt != 0) {
+    SSH_LOG(SSH_LOG_RARE, "Glob error: %s",
+          fileglob);
+    globfree(&globbuf);
+    return;
+  }
+
+  for (i = 0; i < globbuf.gl_pathc; i++) {
+    local_parse_file(session, globbuf.gl_pathv[i], parsing, seen);
+  }
+
+  globfree(&globbuf);
+}
+
 static int ssh_config_parse_line(ssh_session session, const char *line,
     unsigned int count, int *parsing, int seen[]) {
   enum ssh_config_opcode_e opcode;
@@ -361,7 +387,7 @@ static int ssh_config_parse_line(ssh_session session, const char *line,
 
       p = ssh_config_get_str_tok(&s, NULL);
       if (p && *parsing) {
-        local_parse_file(session, p, parsing, seen);
+        local_parse_glob(session, p, parsing, seen);
       }
       break;
     case SOC_HOST: {
diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index a0b40239..8ca097c7 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -10,6 +10,9 @@
 #define LIBSSH_TESTCONFIG2 "libssh_testconfig2.tmp"
 #define LIBSSH_TESTCONFIG3 "libssh_testconfig3.tmp"
 #define LIBSSH_TESTCONFIG4 "libssh_testconfig4.tmp"
+#define LIBSSH_TESTCONFIG5 "libssh_testconfig5.tmp"
+#define LIBSSH_TESTCONFIG6 "libssh_testconfig6.tmp"
+#define LIBSSH_TESTCONFIGGLOB "libssh_testc*[36].tmp"
 
 #define USERNAME "testuser"
 #define PROXYCMD "ssh -q -W %h:%p gateway.example.com"
@@ -25,6 +28,8 @@ static int setup_config_files(void **state)
     unlink(LIBSSH_TESTCONFIG2);
     unlink(LIBSSH_TESTCONFIG3);
     unlink(LIBSSH_TESTCONFIG4);
+    unlink(LIBSSH_TESTCONFIG5);
+    unlink(LIBSSH_TESTCONFIG6);
 
     torture_write_file(LIBSSH_TESTCONFIG1,
                        "User "USERNAME"\nInclude "LIBSSH_TESTCONFIG2"\n\n");
@@ -40,6 +45,13 @@ static int setup_config_files(void **state)
     torture_write_file(LIBSSH_TESTCONFIG4,
                        "Port 123\nPort 456\n");
 
+    /* Testing glob include */
+    torture_write_file(LIBSSH_TESTCONFIG5,
+                        "User "USERNAME"\nInclude "LIBSSH_TESTCONFIGGLOB"\n\n");
+
+    torture_write_file(LIBSSH_TESTCONFIG6,
+                        "ProxyCommand "PROXYCMD"\n\n");
+
     session = ssh_new();
     *state = session;
 
@@ -52,6 +64,8 @@ static int teardown(void **state)
     unlink(LIBSSH_TESTCONFIG2);
     unlink(LIBSSH_TESTCONFIG3);
     unlink(LIBSSH_TESTCONFIG4);
+    unlink(LIBSSH_TESTCONFIG5);
+    unlink(LIBSSH_TESTCONFIG6);
 
     ssh_free(*state);
 
@@ -105,6 +119,29 @@ static void torture_config_double_ports(void **state) {
     assert_true(ret == 0);
 }
 
+static void torture_config_glob(void **state) {
+    ssh_session session = *state;
+    int ret;
+    char *v;
+
+    ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG5);
+    assert_true(ret == 0);
+
+    /* Test the variable presence */
+
+    ret = ssh_options_get(session, SSH_OPTIONS_PROXYCOMMAND, &v);
+    assert_true(ret == 0);
+
+    assert_string_equal(v, PROXYCMD);
+    ssh_string_free_char(v);
+
+    ret = ssh_options_get(session, SSH_OPTIONS_IDENTITY, &v);
+    assert_true(ret == 0);
+
+    assert_string_equal(v, ID_FILE);
+    ssh_string_free_char(v);
+}
+
 int torture_run_tests(void) {
     int rc;
     struct CMUnitTest tests[] = {
@@ -114,6 +151,9 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_config_double_ports,
                                         setup_config_files,
                                         teardown),
+        cmocka_unit_test_setup_teardown(torture_config_glob,
+                                        setup_config_files,
+                                        teardown),
     };
 
 
-- 
2.13.6


From 7cca1bc77fd70ecc80399a05d9cae9f0ea51df7d Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 13 Nov 2017 12:03:52 +0100
Subject: [PATCH 13/21] tests: HostkeyAlgorithms passed from config to options

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_config.c  |  4 ++++
 tests/unittests/torture_options.c | 20 ++++++++++++++++++++
 2 files changed, 24 insertions(+)

diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index 8ca097c7..705cf15f 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -18,6 +18,7 @@
 #define PROXYCMD "ssh -q -W %h:%p gateway.example.com"
 #define ID_FILE "/etc/xxx"
 #define KEXALGORITHMS "ecdh-sha2-nistp521,diffie-hellman-group14-sha1"
+#define HOSTKEYALGORITHMS "ssh-ed25519,ecdsa-sha2-nistp521,ssh-rsa"
 #define MACS "hmac-sha1,hmac-sha2-256"
 
 static int setup_config_files(void **state)
@@ -39,6 +40,7 @@ static int setup_config_files(void **state)
     torture_write_file(LIBSSH_TESTCONFIG3,
                        "\n\nIdentityFile "ID_FILE"\n"
                        "\n\nKexAlgorithms "KEXALGORITHMS"\n"
+                       "\n\nHostKeyAlgorithms "HOSTKEYALGORITHMS"\n"
                        "\n\nMACs "MACS"\n");
 
     /* Multiple Port settings -> parsing returns early. */
@@ -106,6 +108,8 @@ static void torture_config_from_file(void **state) {
 
     assert_string_equal(session->opts.wanted_methods[SSH_KEX], KEXALGORITHMS);
 
+    assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], HOSTKEYALGORITHMS);
+
     assert_string_equal(session->opts.wanted_methods[SSH_MAC_C_S], MACS);
     assert_string_equal(session->opts.wanted_methods[SSH_MAC_S_C], MACS);
 }
diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
index 678d4a4c..24f1814d 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -78,6 +78,25 @@ static void torture_options_set_key_exchange(void **state) {
     assert_false(rc == 0);
 }
 
+static void torture_options_set_hostkey(void **state) {
+    ssh_session session = *state;
+    int rc;
+
+    /* Test known host keys */
+    rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
+    assert_true(rc == 0);
+    assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], "ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
+
+    /* Test one unknown kex */
+    rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "ssh-ed25519,unknown-crap@xxxxxxxxxxx,ssh-rsa");
+    assert_true(rc == 0);
+    assert_string_equal(session->opts.wanted_methods[SSH_HOSTKEYS], "ssh-ed25519,ssh-rsa");
+
+    /* Test all unknown kexes */
+    rc = ssh_options_set(session, SSH_OPTIONS_HOSTKEYS, "unknown-crap@xxxxxxxxxxx,more-crap@xxxxxxxxxxx");
+    assert_false(rc == 0);
+}
+
 static void torture_options_set_macs(void **state) {
     ssh_session session = *state;
     int rc;
@@ -355,6 +374,7 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_options_proxycommand, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_set_ciphers, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_set_key_exchange, setup, teardown),
+        cmocka_unit_test_setup_teardown(torture_options_set_hostkey, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_set_macs, setup, teardown),
         cmocka_unit_test_setup_teardown(torture_options_config_host, setup, teardown)
     };
-- 
2.13.6


From 9992864762f4f426525bb7ef98e147fcae93b0e0 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 13 Nov 2017 13:58:32 +0100
Subject: [PATCH 14/21] tests/config: Verify known_hosts files are applied

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_config.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index 705cf15f..fc8d976b 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -12,6 +12,7 @@
 #define LIBSSH_TESTCONFIG4 "libssh_testconfig4.tmp"
 #define LIBSSH_TESTCONFIG5 "libssh_testconfig5.tmp"
 #define LIBSSH_TESTCONFIG6 "libssh_testconfig6.tmp"
+#define LIBSSH_TESTCONFIG7 "libssh_testconfig7.tmp"
 #define LIBSSH_TESTCONFIGGLOB "libssh_testc*[36].tmp"
 
 #define USERNAME "testuser"
@@ -20,6 +21,8 @@
 #define KEXALGORITHMS "ecdh-sha2-nistp521,diffie-hellman-group14-sha1"
 #define HOSTKEYALGORITHMS "ssh-ed25519,ecdsa-sha2-nistp521,ssh-rsa"
 #define MACS "hmac-sha1,hmac-sha2-256"
+#define USER_KNOWN_HOSTS "%d/my_known_hosts"
+#define GLOBAL_KNOWN_HOSTS "/etc/ssh/my_ssh_known_hosts"
 
 static int setup_config_files(void **state)
 {
@@ -31,6 +34,7 @@ static int setup_config_files(void **state)
     unlink(LIBSSH_TESTCONFIG4);
     unlink(LIBSSH_TESTCONFIG5);
     unlink(LIBSSH_TESTCONFIG6);
+    unlink(LIBSSH_TESTCONFIG7);
 
     torture_write_file(LIBSSH_TESTCONFIG1,
                        "User "USERNAME"\nInclude "LIBSSH_TESTCONFIG2"\n\n");
@@ -54,6 +58,10 @@ static int setup_config_files(void **state)
     torture_write_file(LIBSSH_TESTCONFIG6,
                         "ProxyCommand "PROXYCMD"\n\n");
 
+    torture_write_file(LIBSSH_TESTCONFIG7,
+                        "\tGlobalKnownHostsFile "GLOBAL_KNOWN_HOSTS"\n"
+                        "\tUserKnownHostsFile "USER_KNOWN_HOSTS"\n");
+
     session = ssh_new();
     *state = session;
 
@@ -68,6 +76,7 @@ static int teardown(void **state)
     unlink(LIBSSH_TESTCONFIG4);
     unlink(LIBSSH_TESTCONFIG5);
     unlink(LIBSSH_TESTCONFIG6);
+    unlink(LIBSSH_TESTCONFIG7);
 
     ssh_free(*state);
 
@@ -146,6 +155,20 @@ static void torture_config_glob(void **state) {
     ssh_string_free_char(v);
 }
 
+/**
+ * @brief Verify the known host files are passed from configuration
+ */
+static void torture_config_known_hosts(void **state) {
+    ssh_session session = *state;
+    int ret = 0;
+
+    ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG7);
+    assert_true(ret == 0);
+
+    assert_string_equal(session->opts.knownhosts, USER_KNOWN_HOSTS);
+    assert_string_equal(session->opts.global_knownhosts, GLOBAL_KNOWN_HOSTS);
+}
+
 int torture_run_tests(void) {
     int rc;
     struct CMUnitTest tests[] = {
@@ -158,6 +181,9 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_config_glob,
                                         setup_config_files,
                                         teardown),
+        cmocka_unit_test_setup_teardown(torture_config_known_hosts,
+                                        setup_config_files,
+                                        teardown),
     };
 
 
-- 
2.13.6


From 9ec6851a0d9fcdd5df11e630a88b4bb96f0e01da Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 16 Nov 2017 16:29:20 +0100
Subject: [PATCH 15/21] tests/options: Clean up the configuration file

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_options.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c
index 24f1814d..6aa4658d 100644
--- a/tests/unittests/torture_options.c
+++ b/tests/unittests/torture_options.c
@@ -282,6 +282,7 @@ static void torture_options_proxycommand(void **state) {
     assert_null(session->opts.ProxyCommand);
 }
 
+/* XXX move to torture_config as other config related tests? */
 static void torture_options_config_host(void **state) {
     ssh_session session = *state;
     FILE *config;
@@ -307,6 +308,8 @@ static void torture_options_config_host(void **state) {
     ssh_options_parse_config(session, "test_config");
     assert_int_equal(session->opts.port, 43);
 
+    /* clean up */
+    unlink("test_config");
 }
 
 
-- 
2.13.6


From ef758ff33340b12fbba47fd5fd527d09aaba02cb Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 16 Nov 2017 16:51:58 +0100
Subject: [PATCH 16/21] tests/config: Enable and disable authentication methods

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_config.c | 80 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index fc8d976b..580c5a00 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -13,6 +13,7 @@
 #define LIBSSH_TESTCONFIG5 "libssh_testconfig5.tmp"
 #define LIBSSH_TESTCONFIG6 "libssh_testconfig6.tmp"
 #define LIBSSH_TESTCONFIG7 "libssh_testconfig7.tmp"
+#define LIBSSH_TESTCONFIG8 "libssh_testconfig8.tmp"
 #define LIBSSH_TESTCONFIGGLOB "libssh_testc*[36].tmp"
 
 #define USERNAME "testuser"
@@ -35,6 +36,7 @@ static int setup_config_files(void **state)
     unlink(LIBSSH_TESTCONFIG5);
     unlink(LIBSSH_TESTCONFIG6);
     unlink(LIBSSH_TESTCONFIG7);
+    unlink(LIBSSH_TESTCONFIG8);
 
     torture_write_file(LIBSSH_TESTCONFIG1,
                        "User "USERNAME"\nInclude "LIBSSH_TESTCONFIG2"\n\n");
@@ -62,6 +64,25 @@ static int setup_config_files(void **state)
                         "\tGlobalKnownHostsFile "GLOBAL_KNOWN_HOSTS"\n"
                         "\tUserKnownHostsFile "USER_KNOWN_HOSTS"\n");
 
+    /* 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");
+
     session = ssh_new();
     *state = session;
 
@@ -77,6 +98,7 @@ static int teardown(void **state)
     unlink(LIBSSH_TESTCONFIG5);
     unlink(LIBSSH_TESTCONFIG6);
     unlink(LIBSSH_TESTCONFIG7);
+    unlink(LIBSSH_TESTCONFIG8);
 
     ssh_free(*state);
 
@@ -169,6 +191,61 @@ static void torture_config_known_hosts(void **state) {
     assert_string_equal(session->opts.global_knownhosts, GLOBAL_KNOWN_HOSTS);
 }
 
+/**
+ * @brief Verify the authentication methods from configuration are effective
+ */
+static void torture_config_auth_methods(void **state) {
+    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);
+    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);
+    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);
+    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);
+    assert_false(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH);
+
+    /* no method should be left enabled */
+    assert_int_equal(session->opts.port, 0);
+
+    /* gradually enable them again */
+    ssh_options_set(session, SSH_OPTIONS_HOST, "gss");
+    ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG8);
+    assert_true(ret == 0);
+    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);
+    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);
+    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);
+    assert_true(session->opts.flags & SSH_OPT_FLAG_PUBKEY_AUTH);
+}
+
 int torture_run_tests(void) {
     int rc;
     struct CMUnitTest tests[] = {
@@ -184,6 +261,9 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_config_known_hosts,
                                         setup_config_files,
                                         teardown),
+        cmocka_unit_test_setup_teardown(torture_config_auth_methods,
+                                        setup_config_files,
+                                        teardown),
     };
 
 
-- 
2.13.6


From b58a9453a19a0ed20ed2c47e78fff7baaeec7efc Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 16 Nov 2017 17:21:23 +0100
Subject: [PATCH 17/21] tests/config: Newly parsed options

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_config.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index 580c5a00..1a430a14 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -24,6 +24,7 @@
 #define MACS "hmac-sha1,hmac-sha2-256"
 #define USER_KNOWN_HOSTS "%d/my_known_hosts"
 #define GLOBAL_KNOWN_HOSTS "/etc/ssh/my_ssh_known_hosts"
+#define BIND_ADDRESS "::1"
 
 static int setup_config_files(void **state)
 {
@@ -60,7 +61,10 @@ static int setup_config_files(void **state)
     torture_write_file(LIBSSH_TESTCONFIG6,
                         "ProxyCommand "PROXYCMD"\n\n");
 
+    /* new options */
     torture_write_file(LIBSSH_TESTCONFIG7,
+                        "\tBindAddress "BIND_ADDRESS"\n"
+                        "\tConnectTimeout 30\n"
                         "\tGlobalKnownHostsFile "GLOBAL_KNOWN_HOSTS"\n"
                         "\tUserKnownHostsFile "USER_KNOWN_HOSTS"\n");
 
@@ -178,9 +182,9 @@ static void torture_config_glob(void **state) {
 }
 
 /**
- * @brief Verify the known host files are passed from configuration
+ * @brief Verify the new options are passed from configuration
  */
-static void torture_config_known_hosts(void **state) {
+static void torture_config_new(void **state) {
     ssh_session session = *state;
     int ret = 0;
 
@@ -189,6 +193,8 @@ static void torture_config_known_hosts(void **state) {
 
     assert_string_equal(session->opts.knownhosts, USER_KNOWN_HOSTS);
     assert_string_equal(session->opts.global_knownhosts, GLOBAL_KNOWN_HOSTS);
+    assert_int_equal(session->opts.timeout, 30);
+    assert_string_equal(session->opts.bindaddr, BIND_ADDRESS);
 }
 
 /**
@@ -258,7 +264,7 @@ int torture_run_tests(void) {
         cmocka_unit_test_setup_teardown(torture_config_glob,
                                         setup_config_files,
                                         teardown),
-        cmocka_unit_test_setup_teardown(torture_config_known_hosts,
+        cmocka_unit_test_setup_teardown(torture_config_new,
                                         setup_config_files,
                                         teardown),
         cmocka_unit_test_setup_teardown(torture_config_auth_methods,
-- 
2.13.6


From 48adbdde867ca3456fb1f4b5e19e6d882e9589c5 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Mon, 20 Nov 2017 14:46:41 +0100
Subject: [PATCH 18/21] tests/config: Verify LogLevel from config is applied

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/unittests/torture_config.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/tests/unittests/torture_config.c b/tests/unittests/torture_config.c
index 1a430a14..f8394cd1 100644
--- a/tests/unittests/torture_config.c
+++ b/tests/unittests/torture_config.c
@@ -6,6 +6,8 @@
 #include "libssh/options.h"
 #include "libssh/session.h"
 
+extern LIBSSH_THREAD int ssh_log_level;
+
 #define LIBSSH_TESTCONFIG1 "libssh_testconfig1.tmp"
 #define LIBSSH_TESTCONFIG2 "libssh_testconfig2.tmp"
 #define LIBSSH_TESTCONFIG3 "libssh_testconfig3.tmp"
@@ -65,6 +67,7 @@ static int setup_config_files(void **state)
     torture_write_file(LIBSSH_TESTCONFIG7,
                         "\tBindAddress "BIND_ADDRESS"\n"
                         "\tConnectTimeout 30\n"
+                        "\tLogLevel DEBUG3\n"
                         "\tGlobalKnownHostsFile "GLOBAL_KNOWN_HOSTS"\n"
                         "\tUserKnownHostsFile "USER_KNOWN_HOSTS"\n");
 
@@ -187,6 +190,7 @@ static void torture_config_glob(void **state) {
 static void torture_config_new(void **state) {
     ssh_session session = *state;
     int ret = 0;
+    int verbosity = SSH_LOG_WARNING;
 
     ret = ssh_config_parse_file(session, LIBSSH_TESTCONFIG7);
     assert_true(ret == 0);
@@ -195,6 +199,12 @@ static void torture_config_new(void **state) {
     assert_string_equal(session->opts.global_knownhosts, GLOBAL_KNOWN_HOSTS);
     assert_int_equal(session->opts.timeout, 30);
     assert_string_equal(session->opts.bindaddr, BIND_ADDRESS);
+
+    assert_int_equal(ssh_log_level, SSH_LOG_TRACE);
+    assert_int_equal(session->common.log_verbosity, SSH_LOG_TRACE);
+
+    /* reset to something sane */
+    ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
 }
 
 /**
-- 
2.13.6


From 959142ea6f3ecca8cf7b0175cdf07d3cf0860afc Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Wed, 22 Nov 2017 13:43:56 +0100
Subject: [PATCH 19/21] tests/client/algorithms: Respect global verbosity
 settings

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/client/torture_algorithms.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/client/torture_algorithms.c b/tests/client/torture_algorithms.c
index 6f49eff3..cac59a0f 100644
--- a/tests/client/torture_algorithms.c
+++ b/tests/client/torture_algorithms.c
@@ -85,6 +85,9 @@ static void test_algorithm(ssh_session session,
                            const char *hmac) {
     int rc;
 
+    int verbosity = torture_libssh_verbosity();
+    ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
+
     if (kex != NULL) {
         rc = ssh_options_set(session, SSH_OPTIONS_KEY_EXCHANGE, kex);
         assert_int_equal(rc, SSH_OK);
-- 
2.13.6


From 1ac2d8ee8f51051aa09fd010fa4a77be59a753a4 Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 23 Nov 2017 10:47:27 +0100
Subject: [PATCH 20/21] tests: Give server more time to start

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/torture.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/torture.c b/tests/torture.c
index 545fc2e3..b331c901 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -1006,7 +1006,7 @@ void torture_setup_sshd_server(void **state)
     assert_return_code(rc, errno);
 
     /* Give the process some time to start */
-    usleep(500);
+    usleep(1000);
 
     setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1);
     unsetenv("PAM_WRAPPER");
-- 
2.13.6


From 74bef17506600d8f6e7a71fd002557f5936a7adc Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@xxxxxxxxxx>
Date: Thu, 23 Nov 2017 14:02:22 +0100
Subject: [PATCH 21/21] tests: Do not generate pcap file by default

Signed-off-by: Jakub Jelen <jjelen@xxxxxxxxxx>
---
 tests/torture.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/tests/torture.c b/tests/torture.c
index b331c901..4bd71f19 100644
--- a/tests/torture.c
+++ b/tests/torture.c
@@ -815,6 +815,7 @@ void torture_setup_socket_dir(void **state)
     struct torture_state *s;
     const char *p;
     size_t len;
+    char *env = getenv("TORTURE_GENERATE_PCAP");
 
     s = malloc(sizeof(struct torture_state));
     assert_non_null(s);
@@ -851,7 +852,9 @@ void torture_setup_socket_dir(void **state)
 
     setenv("SOCKET_WRAPPER_DIR", p, 1);
     setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1);
-    setenv("SOCKET_WRAPPER_PCAP_FILE", s->pcap_file, 1);
+    if (env != NULL && env[0] == '1') {
+        setenv("SOCKET_WRAPPER_PCAP_FILE", s->pcap_file, 1);
+    }
 
     *state = s;
 }
-- 
2.13.6


Follow-Ups:
Re: [PATCH] config: Parse KexAlgorithms, MACs, improve IncludeAndreas Schneider <asn@xxxxxxxxxxxxxx>
References:
[PATCH] config: Parse KexAlgorithms, MACs, improve IncludeJakub Jelen <jjelen@xxxxxxxxxx>
Archive administrator: postmaster@lists.cynapses.org