Add a 'password-secret' option which represents the name of an object with the password of the user.
Signed-off-by: Pino Toscano <ptosc...@redhat.com> --- block/ssh.c | 35 ++++++++++++++++++++++++++++++++--- block/trace-events | 1 + docs/qemu-block-drivers.texi | 7 +++++-- qapi/block-core.json | 6 +++++- tests/qemu-iotests/207.out | 2 +- 5 files changed, 44 insertions(+), 7 deletions(-) diff --git a/block/ssh.c b/block/ssh.c index 501933b855..04ae223282 100644 --- a/block/ssh.c +++ b/block/ssh.c @@ -43,6 +43,7 @@ #include "qapi/qmp/qstring.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" +#include "crypto/secret.h" #include "trace.h" /* @@ -499,7 +500,8 @@ static int check_host_key(BDRVSSHState *s, SshHostKeyCheck *hkc, Error **errp) return -EINVAL; } -static int authenticate(BDRVSSHState *s, Error **errp) +static int authenticate(BDRVSSHState *s, BlockdevOptionsSsh *opts, + Error **errp) { int r, ret; int method; @@ -538,9 +540,35 @@ static int authenticate(BDRVSSHState *s, Error **errp) } } + /* + * Try to authenticate with password, if available. + */ + if (method & SSH_AUTH_METHOD_PASSWORD && opts->has_password_secret) { + char *password; + + trace_ssh_option_secret_object(opts->password_secret); + password = qcrypto_secret_lookup_as_utf8(opts->password_secret, errp); + if (!password) { + ret = -EINVAL; + goto out; + } + r = ssh_userauth_password(s->session, NULL, password); + g_free(password); + if (r == SSH_AUTH_ERROR) { + ret = -EINVAL; + session_error_setg(errp, s, "failed to authenticate using " + "password authentication"); + goto out; + } else if (r == SSH_AUTH_SUCCESS) { + /* Authenticated! */ + ret = 0; + goto out; + } + } + ret = -EPERM; error_setg(errp, "failed to authenticate using publickey authentication " - "and the identities held by your ssh-agent"); + "and the identities held by your ssh-agent, or using password"); out: return ret; @@ -785,7 +813,7 @@ static int connect_to_ssh(BDRVSSHState *s, BlockdevOptionsSsh *opts, } /* Authenticate. */ - ret = authenticate(s, errp); + ret = authenticate(s, opts, errp); if (ret < 0) { goto err; } @@ -1376,6 +1404,7 @@ static const char *const ssh_strong_runtime_opts[] = { "user", "host_key_check", "server.", + "password-secret", NULL }; diff --git a/block/trace-events b/block/trace-events index d724df0117..391aae03e6 100644 --- a/block/trace-events +++ b/block/trace-events @@ -186,6 +186,7 @@ ssh_write_return(ssize_t ret, int sftp_err) "sftp_write returned %zd (sftp error ssh_seek(int64_t offset) "seeking to offset=%" PRIi64 ssh_auth_methods(int methods) "auth methods=0x%x" ssh_server_status(int status) "server status=%d" +ssh_option_secret_object(const char *path) "using password from object %s" # curl.c curl_timer_cb(long timeout_ms) "timer callback timeout_ms %ld" diff --git a/docs/qemu-block-drivers.texi b/docs/qemu-block-drivers.texi index 91ab0eceae..c77ef2dd69 100644 --- a/docs/qemu-block-drivers.texi +++ b/docs/qemu-block-drivers.texi @@ -771,8 +771,11 @@ matches a specific fingerprint: (@code{sha1:} can also be used as a prefix, but note that OpenSSH tools only use MD5 to print fingerprints). -Currently authentication must be done using ssh-agent. Other -authentication methods may be supported in future. +The optional @var{password-secret} parameter provides the ID of a +@code{secret} object that contains the password for authenticating. + +Currently authentication must be done using ssh-agent, or providing a +password. Other authentication methods may be supported in future. Note: Many ssh servers do not support an @code{fsync}-style operation. The ssh driver cannot guarantee that disk flush requests are diff --git a/qapi/block-core.json b/qapi/block-core.json index 0d43d4f37c..1244562c7b 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3223,13 +3223,17 @@ # @host-key-check: Defines how and what to check the host key against # (default: known_hosts) # +# @password-secret: ID of a QCryptoSecret object providing a password +# for authentication (since 4.2) +# # Since: 2.9 ## { 'struct': 'BlockdevOptionsSsh', 'data': { 'server': 'InetSocketAddress', 'path': 'str', '*user': 'str', - '*host-key-check': 'SshHostKeyCheck' } } + '*host-key-check': 'SshHostKeyCheck', + '*password-secret': 'str' } } ## diff --git a/tests/qemu-iotests/207.out b/tests/qemu-iotests/207.out index 1239d9d648..5bfdf626b9 100644 --- a/tests/qemu-iotests/207.out +++ b/tests/qemu-iotests/207.out @@ -74,7 +74,7 @@ Job failed: failed to open remote file '/this/is/not/an/existing/path': SFTP ser {"execute": "blockdev-create", "arguments": {"job-id": "job0", "options": {"driver": "ssh", "location": {"host-key-check": {"mode": "none"}, "path": "TEST_DIR/PID-t.img", "server": {"host": "127.0.0.1", "port": "22"}, "user": "invalid user"}, "size": 4194304}}} {"return": {}} -Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent +Job failed: failed to authenticate using publickey authentication and the identities held by your ssh-agent, or using password {"execute": "job-dismiss", "arguments": {"id": "job0"}} {"return": {}} -- 2.21.0