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