mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-24 12:09:58 +00:00
ssh: QAPIfy host-key-check option
This makes the host-key-check option available in blockdev-add. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
16e4bdb1bf
commit
ec2f54182c
92
block/ssh.c
92
block/ssh.c
@ -431,31 +431,35 @@ 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, Error **errp)
|
||||
SshHostKeyCheck *hkc, Error **errp)
|
||||
{
|
||||
/* host_key_check=no */
|
||||
if (strcmp(host_key_check, "no") == 0) {
|
||||
SshHostKeyCheckMode mode;
|
||||
|
||||
if (hkc) {
|
||||
mode = hkc->mode;
|
||||
} else {
|
||||
mode = SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case SSH_HOST_KEY_CHECK_MODE_NONE:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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, 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, errp);
|
||||
}
|
||||
|
||||
/* host_key_check=yes */
|
||||
if (strcmp(host_key_check, "yes") == 0) {
|
||||
case SSH_HOST_KEY_CHECK_MODE_HASH:
|
||||
if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) {
|
||||
return check_host_key_hash(s, hkc->u.hash.hash,
|
||||
LIBSSH2_HOSTKEY_HASH_MD5, 16, errp);
|
||||
} else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) {
|
||||
return check_host_key_hash(s, hkc->u.hash.hash,
|
||||
LIBSSH2_HOSTKEY_HASH_SHA1, 20, errp);
|
||||
}
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
case SSH_HOST_KEY_CHECK_MODE_KNOWN_HOSTS:
|
||||
return check_host_key_knownhosts(s, host, port, errp);
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
error_setg(errp, "unknown host_key_check setting (%s)", host_key_check);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -544,16 +548,22 @@ static QemuOptsList ssh_runtime_opts = {
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Port to connect to",
|
||||
},
|
||||
{
|
||||
.name = "host_key_check",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "Defines how and what to check the host key against",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static bool ssh_process_legacy_socket_options(QDict *output_opts,
|
||||
QemuOpts *legacy_opts,
|
||||
Error **errp)
|
||||
static bool ssh_process_legacy_options(QDict *output_opts,
|
||||
QemuOpts *legacy_opts,
|
||||
Error **errp)
|
||||
{
|
||||
const char *host = qemu_opt_get(legacy_opts, "host");
|
||||
const char *port = qemu_opt_get(legacy_opts, "port");
|
||||
const char *host_key_check = qemu_opt_get(legacy_opts, "host_key_check");
|
||||
|
||||
if (!host && port) {
|
||||
error_setg(errp, "port may not be used without host");
|
||||
@ -565,6 +575,28 @@ static bool ssh_process_legacy_socket_options(QDict *output_opts,
|
||||
qdict_put_str(output_opts, "server.port", port ?: stringify(22));
|
||||
}
|
||||
|
||||
if (host_key_check) {
|
||||
if (strcmp(host_key_check, "no") == 0) {
|
||||
qdict_put_str(output_opts, "host-key-check.mode", "none");
|
||||
} else if (strncmp(host_key_check, "md5:", 4) == 0) {
|
||||
qdict_put_str(output_opts, "host-key-check.mode", "hash");
|
||||
qdict_put_str(output_opts, "host-key-check.type", "md5");
|
||||
qdict_put_str(output_opts, "host-key-check.hash",
|
||||
&host_key_check[4]);
|
||||
} else if (strncmp(host_key_check, "sha1:", 5) == 0) {
|
||||
qdict_put_str(output_opts, "host-key-check.mode", "hash");
|
||||
qdict_put_str(output_opts, "host-key-check.type", "sha1");
|
||||
qdict_put_str(output_opts, "host-key-check.hash",
|
||||
&host_key_check[5]);
|
||||
} else if (strcmp(host_key_check, "yes") == 0) {
|
||||
qdict_put_str(output_opts, "host-key-check.mode", "known_hosts");
|
||||
} else {
|
||||
error_setg(errp, "unknown host_key_check setting (%s)",
|
||||
host_key_check);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -585,7 +617,7 @@ static BlockdevOptionsSsh *ssh_parse_options(QDict *options, Error **errp)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!ssh_process_legacy_socket_options(options, opts, errp)) {
|
||||
if (!ssh_process_legacy_options(options, opts, errp)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -629,16 +661,9 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
{
|
||||
BlockdevOptionsSsh *opts;
|
||||
int r, ret;
|
||||
const char *user, *host_key_check;
|
||||
const char *user;
|
||||
long port = 0;
|
||||
|
||||
host_key_check = qdict_get_try_str(options, "host_key_check");
|
||||
if (!host_key_check) {
|
||||
host_key_check = "yes";
|
||||
} else {
|
||||
qdict_del(options, "host_key_check");
|
||||
}
|
||||
|
||||
opts = ssh_parse_options(options, errp);
|
||||
if (opts == NULL) {
|
||||
return -EINVAL;
|
||||
@ -692,8 +717,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
}
|
||||
|
||||
/* Check the remote host's key against known_hosts. */
|
||||
ret = check_host_key(s, s->inet->host, port, host_key_check,
|
||||
errp);
|
||||
ret = check_host_key(s, s->inet->host, port, opts->host_key_check, errp);
|
||||
if (ret < 0) {
|
||||
goto err;
|
||||
}
|
||||
|
@ -2552,6 +2552,63 @@
|
||||
'*cache-clean-interval': 'int',
|
||||
'*encrypt': 'BlockdevQcow2Encryption' } }
|
||||
|
||||
##
|
||||
# @SshHostKeyCheckMode:
|
||||
#
|
||||
# @none Don't check the host key at all
|
||||
# @hash Compare the host key with a given hash
|
||||
# @known_hosts Check the host key against the known_hosts file
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'enum': 'SshHostKeyCheckMode',
|
||||
'data': [ 'none', 'hash', 'known_hosts' ] }
|
||||
|
||||
##
|
||||
# @SshHostKeyCheckHashType:
|
||||
#
|
||||
# @md5 The given hash is an md5 hash
|
||||
# @sha1 The given hash is an sha1 hash
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'enum': 'SshHostKeyCheckHashType',
|
||||
'data': [ 'md5', 'sha1' ] }
|
||||
|
||||
##
|
||||
# @SshHostKeyHash:
|
||||
#
|
||||
# @type The hash algorithm used for the hash
|
||||
# @hash The expected hash value
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'struct': 'SshHostKeyHash',
|
||||
'data': { 'type': 'SshHostKeyCheckHashType',
|
||||
'hash': 'str' }}
|
||||
|
||||
##
|
||||
# @SshHostKeyDummy:
|
||||
#
|
||||
# For those union branches that don't need additional fields.
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'struct': 'SshHostKeyDummy',
|
||||
'data': {} }
|
||||
|
||||
##
|
||||
# @SshHostKeyCheck:
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'union': 'SshHostKeyCheck',
|
||||
'base': { 'mode': 'SshHostKeyCheckMode' },
|
||||
'discriminator': 'mode',
|
||||
'data': { 'none': 'SshHostKeyDummy',
|
||||
'hash': 'SshHostKeyHash',
|
||||
'known_hosts': 'SshHostKeyDummy' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsSsh:
|
||||
#
|
||||
@ -2562,14 +2619,16 @@
|
||||
# @user: user as which to connect, defaults to current
|
||||
# local user name
|
||||
#
|
||||
# TODO: Expose the host_key_check option in QMP
|
||||
# @host-key-check: Defines how and what to check the host key against
|
||||
# (default: known_hosts)
|
||||
#
|
||||
# Since: 2.9
|
||||
##
|
||||
{ 'struct': 'BlockdevOptionsSsh',
|
||||
'data': { 'server': 'InetSocketAddress',
|
||||
'path': 'str',
|
||||
'*user': 'str' } }
|
||||
'*user': 'str',
|
||||
'*host-key-check': 'SshHostKeyCheck' } }
|
||||
|
||||
|
||||
##
|
||||
|
Loading…
Reference in New Issue
Block a user