If we are running inside the daemon, the remote driver usually declines
URIs without a hostname present to avoid connecting back to itself, and
to avoid accepting a URI that would be handled by a real local driver
later in the probe order.
It is now, however, possible to connect to alternative local daemons so
this special hack based on hostname is insufficiently flexible.
Instead we are willing to connect to a local UNIX socket, provided the
local daemon does not have a driver registered for the URI. In this case
we will then connect to an alternative daemon with a socket path based
on the URI.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
src/driver.h | 2 +
src/libvirt.c | 24 +++++++++
src/remote/remote_daemon_dispatch.c | 11 +++-
src/remote/remote_driver.c | 100 ++++++++++++++++++++++++++----------
src/remote/remote_driver.h | 3 --
5 files changed, 109 insertions(+), 31 deletions(-)
diff --git a/src/driver.h b/src/driver.h
index b4e50ab987..e8f0c0ebdf 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -107,6 +107,8 @@ int virSetSharedNWFilterDriver(virNWFilterDriverPtr driver)
ATTRIBUTE_RETURN_CHE
int virSetSharedSecretDriver(virSecretDriverPtr driver) ATTRIBUTE_RETURN_CHECK;
int virSetSharedStorageDriver(virStorageDriverPtr driver) ATTRIBUTE_RETURN_CHECK;
+bool virHasDriverForURIScheme(const char *scheme);
+
int virDriverLoadModule(const char *name,
const char *regfunc,
bool required);
diff --git a/src/libvirt.c b/src/libvirt.c
index 0a81cbfb99..d81b58aa10 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -689,6 +689,30 @@ virRegisterConnectDriver(virConnectDriverPtr driver,
}
+/**
+ * virHasDriverForURIScheme:
+ * @scheme: the URI scheme
+ *
+ * Determine if there is a driver registered that explicitly
+ * handles URIs with the scheme @scheme.
+ *
+ * Returns: true if a driver is registered
+ */
+bool virHasDriverForURIScheme(const char *scheme)
+{
+ size_t i, j;
+ for (i = 0; i < virConnectDriverTabCount; i++) {
+ if (!virConnectDriverTab[i]->uriSchemes)
+ continue;
+ for (j = 0; virConnectDriverTab[i]->uriSchemes[j]; j++) {
+ if (STREQ(virConnectDriverTab[i]->uriSchemes[j], scheme))
+ return true;
+ }
+ }
+
+ return false;
+}
+
/**
* virRegisterStateDriver:
* @driver: pointer to a driver block
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index a8a5932d71..1eed9a0b38 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -1833,7 +1833,16 @@ remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
priv->networkConn = virObjectRef(priv->conn);
priv->nodedevConn = virObjectRef(priv->conn);
priv->nwfilterConn = virObjectRef(priv->conn);
- priv->secretConn = virObjectRef(priv->conn);
+ if (STRPREFIX(name, "secret:///")) {
+ priv->secretConn = virObjectRef(priv->conn);
+ } else {
+ const char *uri = geteuid() == 0 ? "secret:///system" :
"secret:///session";
+ priv->secretConn = flags & VIR_CONNECT_RO
+ ? virConnectOpenReadOnly(uri)
+ : virConnectOpen(uri);
+ if (!priv->secretConn)
+ goto cleanup;
+ }
priv->storageConn = virObjectRef(priv->conn);
/* force update the @readonly attribute which was inherited from the
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index b4b034423a..a3ace44b06 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -51,6 +51,7 @@
#include "virauth.h"
#include "virauthconfig.h"
#include "virstring.h"
+#include "c-ctype.h"
#define VIR_FROM_THIS VIR_FROM_REMOTE
@@ -711,8 +712,7 @@ remoteConnectSupportsFeatureUnlocked(virConnectPtr conn,
continue; \
}
-
-static char *remoteGetUNIXSocketNonRoot(void)
+static char *remoteGetUNIXSocketNonRoot(const char *daemon_name)
{
char *sockname = NULL;
char *userdir = virGetUserRuntimeDirectory();
@@ -720,23 +720,23 @@ static char *remoteGetUNIXSocketNonRoot(void)
if (!userdir)
return NULL;
- if (virAsprintf(&sockname, "%s/" LIBVIRTD_USER_UNIX_SOCKET, userdir)
< 0) {
+ if (virAsprintf(&sockname, "%s/%s-sock", userdir,
+ inside_daemon ? daemon_name : "libvirt") < 0) {
VIR_FREE(userdir);
return NULL;
}
- VIR_FREE(userdir);
VIR_DEBUG("Chosen UNIX sockname %s", sockname);
return sockname;
}
-static char *remoteGetUNIXSocketRoot(unsigned int flags)
+static char *remoteGetUNIXSocketRoot(const char *daemon_name, unsigned int flags)
{
char *sockname = NULL;
- if (VIR_STRDUP(sockname,
- flags & VIR_DRV_OPEN_REMOTE_RO ?
- LIBVIRTD_PRIV_UNIX_SOCKET_RO : LIBVIRTD_PRIV_UNIX_SOCKET) < 0)
+ if (virAsprintf(&sockname, "%s/%s-%s", LOCALSTATEDIR
"/run/libvirt",
+ inside_daemon ? daemon_name : "libvirt",
+ flags & VIR_DRV_OPEN_REMOTE_RO ? "sock-ro" :
"sock") < 0)
return NULL;
VIR_DEBUG("Chosen UNIX sockname %s", sockname);
@@ -768,6 +768,8 @@ doRemoteOpen(virConnectPtr conn,
struct private_data *priv,
const char *driver_str,
const char *transport_str,
+ const char *daemon_name,
+ const char *daemon_env,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
virConfPtr conf,
unsigned int flags)
@@ -1004,7 +1006,7 @@ doRemoteOpen(virConnectPtr conn,
goto failed;
}
- if (!(sockname = remoteGetUNIXSocketRoot(flags)))
+ if (!(sockname = remoteGetUNIXSocketRoot(daemon_name, flags)))
goto failed;
}
@@ -1039,7 +1041,7 @@ doRemoteOpen(virConnectPtr conn,
goto failed;
}
- if (!(sockname = remoteGetUNIXSocketRoot(flags)))
+ if (!(sockname = remoteGetUNIXSocketRoot(daemon_name, flags)))
goto failed;
}
@@ -1067,20 +1069,21 @@ doRemoteOpen(virConnectPtr conn,
case trans_unix:
if (!sockname) {
if (flags & VIR_DRV_OPEN_REMOTE_USER)
- sockname = remoteGetUNIXSocketNonRoot();
+ sockname = remoteGetUNIXSocketNonRoot(daemon_name);
else
- sockname = remoteGetUNIXSocketRoot(flags);
+ sockname = remoteGetUNIXSocketRoot(daemon_name, flags);
if (!sockname)
goto failed;
}
- if ((flags & VIR_DRV_OPEN_REMOTE_AUTOSTART) &&
- !(daemonPath = virFileFindResourceFull("libvirtd",
- NULL, NULL,
- abs_topbuilddir "/src",
- SBINDIR,
- "LIBVIRTD_PATH")))
- goto failed;
+ if (flags & VIR_DRV_OPEN_REMOTE_AUTOSTART) {
+ if (!(daemonPath = virFileFindResourceFull(daemon_name,
+ NULL, NULL,
+ abs_topbuilddir "/src",
+ SBINDIR,
+ daemon_env)))
+ goto failed;
+ }
if (!(priv->client = virNetClientNewUNIX(sockname,
flags &
VIR_DRV_OPEN_REMOTE_AUTOSTART,
@@ -1104,7 +1107,7 @@ doRemoteOpen(virConnectPtr conn,
goto failed;
}
- if (!(sockname = remoteGetUNIXSocketRoot(flags)))
+ if (!(sockname = remoteGetUNIXSocketRoot(daemon_name, flags)))
goto failed;
}
@@ -1312,6 +1315,9 @@ remoteAllocPrivateData(void)
return priv;
}
+
+#define DRIVER_SCHEME_CHRS "abcdefghijklmnopqrstuvwxyz"
+
static virDrvOpenStatus
remoteConnectOpen(virConnectPtr conn,
virConnectAuthPtr auth,
@@ -1324,14 +1330,53 @@ remoteConnectOpen(virConnectPtr conn,
const char *autostart = virGetEnvBlockSUID("LIBVIRT_AUTOSTART");
char *driver = NULL;
char *transport = NULL;
+ char *daemon_name = NULL;
+ char *daemon_env = NULL;
- if (conn->uri &&
- remoteSplitURIScheme(conn->uri, &driver, &transport) < 0)
- goto cleanup;
+ if (conn->uri) {
+ if (remoteSplitURIScheme(conn->uri, &driver, &transport) < 0)
+ goto cleanup;
- if (inside_daemon && (!conn->uri || !conn->uri->server)) {
- ret = VIR_DRV_OPEN_DECLINED;
- goto cleanup;
+ if (strspn(driver, DRIVER_SCHEME_CHRS) < strlen(driver)) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("Invalid character in driver '%s'"),
driver);
+ goto cleanup;
+ }
+
+ if (inside_daemon) {
+ char *tmp;
+ if (virAsprintf(&daemon_name, "virt%sd", driver) < 0 ||
+ virAsprintf(&daemon_env, "virt%sd_path", driver) < 0)
+ goto cleanup;
+
+ tmp = daemon_env;
+ while (*tmp) {
+ *tmp = c_toupper(*tmp);
+ tmp++;
+ }
+ } else {
+ if (VIR_STRDUP(daemon_name, "libvirtd") < 0 ||
+ VIR_STRDUP(daemon_env, "LIBVIRTD_PATH") < 0)
+ goto cleanup;
+ }
+ }
+
+ if (inside_daemon) {
+ if (!conn->uri) {
+ ret = VIR_DRV_OPEN_DECLINED;
+ goto cleanup;
+ }
+
+ /*
+ * If we're inside the daemon and there's a driver
+ * registered for this URI scheme, we should not
+ * handle this URI ourselves
+ */
+ if (!conn->uri->server &&
+ virHasDriverForURIScheme(driver)) {
+ ret = VIR_DRV_OPEN_DECLINED;
+ goto cleanup;
+ }
}
if (!(priv = remoteAllocPrivateData()))
@@ -1378,7 +1423,8 @@ remoteConnectOpen(virConnectPtr conn,
}
}
- ret = doRemoteOpen(conn, priv, driver, transport, auth, conf, rflags);
+ ret = doRemoteOpen(conn, priv, driver, transport,
+ daemon_name, daemon_env, auth, conf, rflags);
if (ret != VIR_DRV_OPEN_SUCCESS) {
conn->privateData = NULL;
remoteDriverUnlock(priv);
diff --git a/src/remote/remote_driver.h b/src/remote/remote_driver.h
index ef53179833..f6e3deb3d0 100644
--- a/src/remote/remote_driver.h
+++ b/src/remote/remote_driver.h
@@ -34,9 +34,6 @@ unsigned long remoteVersion(void);
# define LIBVIRTD_LISTEN_ADDR NULL
# define LIBVIRTD_TLS_PORT "16514"
# define LIBVIRTD_TCP_PORT "16509"
-# define LIBVIRTD_PRIV_UNIX_SOCKET LOCALSTATEDIR "/run/libvirt/libvirt-sock"
-# define LIBVIRTD_PRIV_UNIX_SOCKET_RO LOCALSTATEDIR
"/run/libvirt/libvirt-sock-ro"
-# define LIBVIRTD_USER_UNIX_SOCKET "libvirt-sock"
/* Defaults for PKI directory. */
# define LIBVIRT_PKI_DIR SYSCONFDIR "/pki"
--
2.14.3