05bba0
From 6151164b6f33870c511a7f5f0f64356bb8fe2ff2 Mon Sep 17 00:00:00 2001
05bba0
From: Richard Jones <rjones@redhat.com>
05bba0
Date: Mon, 8 Jun 2015 11:56:56 +0200
05bba0
Subject: [PATCH 03/30] block/ssh: Propagate errors through check_host_key()
05bba0
05bba0
Message-id: <1433764620-20506-3-git-send-email-rjones@redhat.com>
05bba0
Patchwork-id: 65479
05bba0
O-Subject: [RHEL-7.2 qemu-kvm PATCH 2/6] block/ssh: Propagate errors through check_host_key()
05bba0
Bugzilla: 1226683
05bba0
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
05bba0
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
05bba0
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
05bba0
05bba0
From: Markus Armbruster <armbru@redhat.com>
05bba0
05bba0
Signed-off-by: Markus Armbruster <armbru@redhat.com>
05bba0
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
05bba0
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
05bba0
05bba0
Upstream-status: 01c2b265fce921d6460e06f5af4dfb405119cbab
05bba0
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
05bba0
---
05bba0
 block/ssh.c | 68 ++++++++++++++++++++++++++++++++++++++++++++-----------------
05bba0
 1 file changed, 49 insertions(+), 19 deletions(-)
05bba0
05bba0
diff --git a/block/ssh.c b/block/ssh.c
05bba0
index 1f7c6ed..6ffcff1 100644
05bba0
--- a/block/ssh.c
05bba0
+++ b/block/ssh.c
05bba0
@@ -106,6 +106,31 @@ static void ssh_state_free(BDRVSSHState *s)
05bba0
     }
05bba0
 }
05bba0
 
05bba0
+static void GCC_FMT_ATTR(3, 4)
05bba0
+session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
05bba0
+{
05bba0
+    va_list args;
05bba0
+    char *msg;
05bba0
+
05bba0
+    va_start(args, fs);
05bba0
+    msg = g_strdup_vprintf(fs, args);
05bba0
+    va_end(args);
05bba0
+
05bba0
+    if (s->session) {
05bba0
+        char *ssh_err;
05bba0
+        int ssh_err_code;
05bba0
+
05bba0
+        /* This is not an errno.  See <libssh2.h>. */
05bba0
+        ssh_err_code = libssh2_session_last_error(s->session,
05bba0
+                                                  &ssh_err, NULL, 0);
05bba0
+        error_setg(errp, "%s: %s (libssh2 error code: %d)",
05bba0
+                   msg, ssh_err, ssh_err_code);
05bba0
+    } else {
05bba0
+        error_setg(errp, "%s", msg);
05bba0
+    }
05bba0
+    g_free(msg);
05bba0
+}
05bba0
+
05bba0
 /* Wrappers around error_report which make sure to dump as much
05bba0
  * information from libssh2 as possible.
05bba0
  */
05bba0
@@ -242,7 +267,7 @@ static void ssh_parse_filename(const char *filename, QDict *options,
05bba0
 }
05bba0
 
05bba0
 static int check_host_key_knownhosts(BDRVSSHState *s,
05bba0
-                                     const char *host, int port)
05bba0
+                                     const char *host, int port, Error **errp)
05bba0
 {
05bba0
     const char *home;
05bba0
     char *knh_file = NULL;
05bba0
@@ -256,14 +281,15 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
05bba0
     hostkey = libssh2_session_hostkey(s->session, &len, &type);
05bba0
     if (!hostkey) {
05bba0
         ret = -EINVAL;
05bba0
-        session_error_report(s, "failed to read remote host key");
05bba0
+        session_error_setg(errp, s, "failed to read remote host key");
05bba0
         goto out;
05bba0
     }
05bba0
 
05bba0
     knh = libssh2_knownhost_init(s->session);
05bba0
     if (!knh) {
05bba0
         ret = -EINVAL;
05bba0
-        session_error_report(s, "failed to initialize known hosts support");
05bba0
+        session_error_setg(errp, s,
05bba0
+                           "failed to initialize known hosts support");
05bba0
         goto out;
05bba0
     }
05bba0
 
05bba0
@@ -288,21 +314,23 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
05bba0
         break;
05bba0
     case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
05bba0
         ret = -EINVAL;
05bba0
-        session_error_report(s, "host key does not match the one in known_hosts (found key %s)",
05bba0
-                             found->key);
05bba0
+        session_error_setg(errp, s,
05bba0
+                      "host key does not match the one in known_hosts"
05bba0
+                      " (found key %s)", found->key);
05bba0
         goto out;
05bba0
     case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
05bba0
         ret = -EINVAL;
05bba0
-        session_error_report(s, "no host key was found in known_hosts");
05bba0
+        session_error_setg(errp, s, "no host key was found in known_hosts");
05bba0
         goto out;
05bba0
     case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
05bba0
         ret = -EINVAL;
05bba0
-        session_error_report(s, "failure matching the host key with known_hosts");
05bba0
+        session_error_setg(errp, s,
05bba0
+                      "failure matching the host key with known_hosts");
05bba0
         goto out;
05bba0
     default:
05bba0
         ret = -EINVAL;
05bba0
-        session_error_report(s, "unknown error matching the host key with known_hosts (%d)",
05bba0
-                             r);
05bba0
+        session_error_setg(errp, s, "unknown error matching the host key"
05bba0
+                      " with known_hosts (%d)", r);
05bba0
         goto out;
05bba0
     }
05bba0
 
05bba0
@@ -357,20 +385,20 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
05bba0
 
05bba0
 static int
05bba0
 check_host_key_hash(BDRVSSHState *s, const char *hash,
05bba0
-                    int hash_type, size_t fingerprint_len)
05bba0
+                    int hash_type, size_t fingerprint_len, Error **errp)
05bba0
 {
05bba0
     const char *fingerprint;
05bba0
 
05bba0
     fingerprint = libssh2_hostkey_hash(s->session, hash_type);
05bba0
     if (!fingerprint) {
05bba0
-        session_error_report(s, "failed to read remote host key");
05bba0
+        session_error_setg(errp, s, "failed to read remote host key");
05bba0
         return -EINVAL;
05bba0
     }
05bba0
 
05bba0
     if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
05bba0
                            hash) != 0) {
05bba0
-        error_report("remote host key does not match host_key_check '%s'",
05bba0
-                     hash);
05bba0
+        error_setg(errp, "remote host key does not match host_key_check '%s'",
05bba0
+                   hash);
05bba0
         return -EPERM;
05bba0
     }
05bba0
 
05bba0
@@ -378,7 +406,7 @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
05bba0
 }
05bba0
 
05bba0
 static int check_host_key(BDRVSSHState *s, const char *host, int port,
05bba0
-                          const char *host_key_check)
05bba0
+                          const char *host_key_check, Error **errp)
05bba0
 {
05bba0
     /* host_key_check=no */
05bba0
     if (strcmp(host_key_check, "no") == 0) {
05bba0
@@ -388,21 +416,21 @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
05bba0
     /* host_key_check=md5:xx:yy:zz:... */
05bba0
     if (strncmp(host_key_check, "md5:", 4) == 0) {
05bba0
         return check_host_key_hash(s, &host_key_check[4],
05bba0
-                                   LIBSSH2_HOSTKEY_HASH_MD5, 16);
05bba0
+                                   LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
05bba0
     }
05bba0
 
05bba0
     /* host_key_check=sha1:xx:yy:zz:... */
05bba0
     if (strncmp(host_key_check, "sha1:", 5) == 0) {
05bba0
         return check_host_key_hash(s, &host_key_check[5],
05bba0
-                                   LIBSSH2_HOSTKEY_HASH_SHA1, 20);
05bba0
+                                   LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
05bba0
     }
05bba0
 
05bba0
     /* host_key_check=yes */
05bba0
     if (strcmp(host_key_check, "yes") == 0) {
05bba0
-        return check_host_key_knownhosts(s, host, port);
05bba0
+        return check_host_key_knownhosts(s, host, port, errp);
05bba0
     }
05bba0
 
05bba0
-    error_report("unknown host_key_check setting (%s)", host_key_check);
05bba0
+    error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
05bba0
     return -EINVAL;
05bba0
 }
05bba0
 
05bba0
@@ -541,8 +569,10 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
05bba0
     }
05bba0
 
05bba0
     /* Check the remote host's key against known_hosts. */
05bba0
-    ret = check_host_key(s, host, port, host_key_check);
05bba0
+    ret = check_host_key(s, host, port, host_key_check, &err);
05bba0
     if (ret < 0) {
05bba0
+        qerror_report_err(err);
05bba0
+        error_free(err);
05bba0
         goto err;
05bba0
     }
05bba0
 
05bba0
-- 
05bba0
1.8.3.1
05bba0