block/ssh: Propagate errors through check_host_key()

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Markus Armbruster 2014-05-16 11:00:13 +02:00 committed by Stefan Hajnoczi
parent 04bc7c0e38
commit 01c2b265fc

View File

@ -106,6 +106,31 @@ static void ssh_state_free(BDRVSSHState *s)
}
}
static void GCC_FMT_ATTR(3, 4)
session_error_setg(Error **errp, BDRVSSHState *s, const char *fs, ...)
{
va_list args;
char *msg;
va_start(args, fs);
msg = g_strdup_vprintf(fs, args);
va_end(args);
if (s->session) {
char *ssh_err;
int ssh_err_code;
/* This is not an errno. See <libssh2.h>. */
ssh_err_code = libssh2_session_last_error(s->session,
&ssh_err, NULL, 0);
error_setg(errp, "%s: %s (libssh2 error code: %d)",
msg, ssh_err, ssh_err_code);
} else {
error_setg(errp, "%s", msg);
}
g_free(msg);
}
/* Wrappers around error_report which make sure to dump as much
* information from libssh2 as possible.
*/
@ -242,7 +267,7 @@ static void ssh_parse_filename(const char *filename, QDict *options,
}
static int check_host_key_knownhosts(BDRVSSHState *s,
const char *host, int port)
const char *host, int port, Error **errp)
{
const char *home;
char *knh_file = NULL;
@ -256,14 +281,15 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
hostkey = libssh2_session_hostkey(s->session, &len, &type);
if (!hostkey) {
ret = -EINVAL;
session_error_report(s, "failed to read remote host key");
session_error_setg(errp, s, "failed to read remote host key");
goto out;
}
knh = libssh2_knownhost_init(s->session);
if (!knh) {
ret = -EINVAL;
session_error_report(s, "failed to initialize known hosts support");
session_error_setg(errp, s,
"failed to initialize known hosts support");
goto out;
}
@ -288,21 +314,23 @@ static int check_host_key_knownhosts(BDRVSSHState *s,
break;
case LIBSSH2_KNOWNHOST_CHECK_MISMATCH:
ret = -EINVAL;
session_error_report(s, "host key does not match the one in known_hosts (found key %s)",
found->key);
session_error_setg(errp, s,
"host key does not match the one in known_hosts"
" (found key %s)", found->key);
goto out;
case LIBSSH2_KNOWNHOST_CHECK_NOTFOUND:
ret = -EINVAL;
session_error_report(s, "no host key was found in known_hosts");
session_error_setg(errp, s, "no host key was found in known_hosts");
goto out;
case LIBSSH2_KNOWNHOST_CHECK_FAILURE:
ret = -EINVAL;
session_error_report(s, "failure matching the host key with known_hosts");
session_error_setg(errp, s,
"failure matching the host key with known_hosts");
goto out;
default:
ret = -EINVAL;
session_error_report(s, "unknown error matching the host key with known_hosts (%d)",
r);
session_error_setg(errp, s, "unknown error matching the host key"
" with known_hosts (%d)", r);
goto out;
}
@ -357,20 +385,20 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
static int
check_host_key_hash(BDRVSSHState *s, const char *hash,
int hash_type, size_t fingerprint_len)
int hash_type, size_t fingerprint_len, Error **errp)
{
const char *fingerprint;
fingerprint = libssh2_hostkey_hash(s->session, hash_type);
if (!fingerprint) {
session_error_report(s, "failed to read remote host key");
session_error_setg(errp, s, "failed to read remote host key");
return -EINVAL;
}
if(compare_fingerprint((unsigned char *) fingerprint, fingerprint_len,
hash) != 0) {
error_report("remote host key does not match host_key_check '%s'",
hash);
error_setg(errp, "remote host key does not match host_key_check '%s'",
hash);
return -EPERM;
}
@ -378,7 +406,7 @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
}
static int check_host_key(BDRVSSHState *s, const char *host, int port,
const char *host_key_check)
const char *host_key_check, Error **errp)
{
/* host_key_check=no */
if (strcmp(host_key_check, "no") == 0) {
@ -388,21 +416,21 @@ static int check_host_key(BDRVSSHState *s, const char *host, int port,
/* host_key_check=md5:xx:yy:zz:... */
if (strncmp(host_key_check, "md5:", 4) == 0) {
return check_host_key_hash(s, &host_key_check[4],
LIBSSH2_HOSTKEY_HASH_MD5, 16);
LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
}
/* host_key_check=sha1:xx:yy:zz:... */
if (strncmp(host_key_check, "sha1:", 5) == 0) {
return check_host_key_hash(s, &host_key_check[5],
LIBSSH2_HOSTKEY_HASH_SHA1, 20);
LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
}
/* host_key_check=yes */
if (strcmp(host_key_check, "yes") == 0) {
return check_host_key_knownhosts(s, host, port);
return check_host_key_knownhosts(s, host, port, errp);
}
error_report("unknown host_key_check setting (%s)", host_key_check);
error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
return -EINVAL;
}
@ -541,8 +569,10 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
}
/* Check the remote host's key against known_hosts. */
ret = check_host_key(s, host, port, host_key_check);
ret = check_host_key(s, host, port, host_key_check, &err);
if (ret < 0) {
qerror_report_err(err);
error_free(err);
goto err;
}