This patch adds URI options to support libssh2 transport in the remote driver. A new transport sceme is introduced eg. "qemu+libssh://..." that utilizes the libssh2 code added in previous patches. The libssh2 code requires the authentication callback to be able to perform keyboard-interactive authentication or to ask t passprhases or add host keys to known hosts database. Added URI components: - known_hosts - path to a knownHosts file in OpenSSH format to check for known ssh host keys - no_verify - this old option is abused to indicate desired behavior, what to do while checking host keys: options: - normal: behave as ssh, ask to add a new key, reject unknown - auto_add: add new keys automaticaly, reject unknown - ignore: don't check host key. *src/remote/remote_driver.c: -Clean up whitespace between function name and parentheses. - Add libssh2 transport scheme - Add URI components to configure libssh2 transport TODO: - Add documentation to web-page documents and man pages regarding new URI options - Add support for tunelled cleartext passwords? --- src/remote/remote_driver.c | 116 ++++++++++++++++++++++++++++++++------------ 1 files changed, 84 insertions(+), 32 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 7580477..0787775 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -304,12 +304,14 @@ enum virDrvOpenRemoteFlags { * - xxx+tcp:/// -> TCP connection to localhost * - xxx+unix:/// -> UNIX domain socket * - xxx:/// -> UNIX domain socket + * - xxx+ssh:/// -> SSH connection (legacy) + * - xxx+libssh:/// -> SSH connection (using libssh2) */ static int -doRemoteOpen (virConnectPtr conn, - struct private_data *priv, - virConnectAuthPtr auth ATTRIBUTE_UNUSED, - unsigned int flags) +doRemoteOpen(virConnectPtr conn, + struct private_data *priv, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + unsigned int flags) { struct qparam_set *vars = NULL; char *transport_str = NULL; @@ -317,6 +319,7 @@ doRemoteOpen (virConnectPtr conn, trans_tls, trans_unix, trans_ssh, + trans_libssh, trans_ext, trans_tcp, } transport; @@ -345,9 +348,9 @@ doRemoteOpen (virConnectPtr conn, else transport = trans_unix; } else { - if (STRCASEEQ (transport_str, "tls")) + if (STRCASEEQ(transport_str, "tls")) transport = trans_tls; - else if (STRCASEEQ (transport_str, "unix")) { + else if (STRCASEEQ(transport_str, "unix")) { if (conn->uri->server) { remoteError(VIR_ERR_INVALID_ARG, _("using unix socket and remote " @@ -357,16 +360,18 @@ doRemoteOpen (virConnectPtr conn, } else { transport = trans_unix; } - } else if (STRCASEEQ (transport_str, "ssh")) + } else if (STRCASEEQ(transport_str, "ssh")) transport = trans_ssh; - else if (STRCASEEQ (transport_str, "ext")) + else if (STRCASEEQ(transport_str, "libssh")) + transport = trans_libssh; + else if (STRCASEEQ(transport_str, "ext")) transport = trans_ext; - else if (STRCASEEQ (transport_str, "tcp")) + else if (STRCASEEQ(transport_str, "tcp")) transport = trans_tcp; else { remoteError(VIR_ERR_INVALID_ARG, "%s", _("remote_open: transport in URL not recognised " - "(should be tls|unix|ssh|ext|tcp)")); + "(should be tls|unix|ssh|ext|tcp|libssh)")); return VIR_DRV_OPEN_ERROR; } } @@ -384,6 +389,8 @@ doRemoteOpen (virConnectPtr conn, bool sanity = true, verify = true, tty ATTRIBUTE_UNUSED = true; char *pkipath = NULL, *keyfile = NULL; + char *knownHostsVerify = NULL, *knownHosts = NULL; + /* Return code from this function, and the private data. */ int retcode = VIR_DRV_OPEN_ERROR; @@ -430,49 +437,57 @@ doRemoteOpen (virConnectPtr conn, for (i = 0; i < vars->n; i++) { var = &vars->p[i]; - if (STRCASEEQ (var->name, "name")) { + if (STRCASEEQ(var->name, "name")) { VIR_FREE(name); - name = strdup (var->value); + name = strdup(var->value); if (!name) goto out_of_memory; var->ignore = 1; - } else if (STRCASEEQ (var->name, "command")) { + } else if (STRCASEEQ(var->name, "command")) { VIR_FREE(command); - command = strdup (var->value); + command = strdup(var->value); if (!command) goto out_of_memory; var->ignore = 1; - } else if (STRCASEEQ (var->name, "socket")) { + } else if (STRCASEEQ(var->name, "socket")) { VIR_FREE(sockname); - sockname = strdup (var->value); + sockname = strdup(var->value); if (!sockname) goto out_of_memory; var->ignore = 1; - } else if (STRCASEEQ (var->name, "auth")) { + } else if (STRCASEEQ(var->name, "auth")) { VIR_FREE(authtype); - authtype = strdup (var->value); + authtype = strdup(var->value); if (!authtype) goto out_of_memory; var->ignore = 1; - } else if (STRCASEEQ (var->name, "netcat")) { + } else if (STRCASEEQ(var->name, "netcat")) { VIR_FREE(netcat); - netcat = strdup (var->value); + netcat = strdup(var->value); if (!netcat) goto out_of_memory; var->ignore = 1; - } else if (STRCASEEQ (var->name, "keyfile")) { + } else if (STRCASEEQ(var->name, "keyfile")) { VIR_FREE(keyfile); - keyfile = strdup (var->value); + keyfile = strdup(var->value); if (!keyfile) goto out_of_memory; - } else if (STRCASEEQ (var->name, "no_sanity")) { + } else if (STRCASEEQ(var->name, "no_sanity")) { sanity = atoi(var->value) == 0; var->ignore = 1; - } else if (STRCASEEQ (var->name, "no_verify")) { - verify = atoi (var->value) == 0; + } else if (STRCASEEQ(var->name, "no_verify")) { + VIR_FREE(knownHostsVerify); + knownHostsVerify = strdup(var->value); + if (!knownHostsVerify) goto out_of_memory; + verify = atoi(var->value) == 0; var->ignore = 1; - } else if (STRCASEEQ (var->name, "no_tty")) { - tty = atoi (var->value) == 0; + } else if (STRCASEEQ(var->name, "no_tty")) { + tty = atoi(var->value) == 0; var->ignore = 1; } else if (STRCASEEQ(var->name, "pkipath")) { VIR_FREE(pkipath); pkipath = strdup(var->value); if (!pkipath) goto out_of_memory; var->ignore = 1; + } else if (STRCASEEQ(var->name, "known_hosts")) { + VIR_FREE(knownHosts); + knownHosts = strdup(var->value); + if (!knownHosts) goto out_of_memory; + var->ignore = 1; } else { VIR_DEBUG("passing through variable '%s' ('%s') to remote end", var->name, var->value); @@ -565,6 +580,34 @@ doRemoteOpen (virConnectPtr conn, break; + case trans_libssh: + if (!sockname) { + if (flags & VIR_DRV_OPEN_REMOTE_RO) + sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO); + else + sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET); + if (sockname == NULL) + goto out_of_memory; + } + + VIR_DEBUG("Starting LibSSH2 session"); + + priv->client = virNetClientNewLibSSH(priv->hostname, + port, + username, + NULL, + netcat, + sockname, + knownHosts, + knownHostsVerify, + keyfile, + auth); + if (!priv->client) + goto failed; + + priv->is_secure = 1; + break; + #ifndef WIN32 case trans_unix: if (!sockname) { @@ -2569,18 +2612,27 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv, { struct remote_auth_list_ret ret; int err, type = REMOTE_AUTH_NONE; + virErrorPtr verr; memset(&ret, 0, sizeof ret); err = call (conn, priv, 0, REMOTE_PROC_AUTH_LIST, (xdrproc_t) xdr_void, (char *) NULL, (xdrproc_t) xdr_remote_auth_list_ret, (char *) &ret); + if (err < 0) { - virErrorPtr verr = virGetLastError(); - if (verr && verr->code == VIR_ERR_NO_SUPPORT) { - /* Missing RPC - old server - ignore */ - virResetLastError(); - return 0; + if ((verr = virGetLastError())) { + if (verr->code == VIR_ERR_NO_SUPPORT) { + /* Missing RPC - old server - ignore */ + virResetLastError(); + return 0; + } + + if (verr->code == VIR_ERR_LIBSSH_REMOTE_COMMAND) { + virResetLastError(); + remoteError(VIR_ERR_LIBSSH_REMOTE_COMMAND, "%s", + _("Remote daemon is not running or remote command has failed")); + } } return -1; } -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list