Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
daemon/libvirtd.h | 2 +
daemon/remote.c | 202 +++++++++++++++++++++++++++++++++++++++++++
src/remote/remote_driver.c | 133 +++++++++++++++++++++++++++-
src/remote/remote_protocol.x | 45 +++++++++-
src/remote_protocol-structs | 19 ++++
5 files changed, 399 insertions(+), 2 deletions(-)
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index 09d505d..b570746 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -64,6 +64,8 @@ struct daemonClientPrivate {
size_t nstorageEventCallbacks;
daemonClientEventCallbackPtr *nodeDeviceEventCallbacks;
size_t nnodeDeviceEventCallbacks;
+ daemonClientEventCallbackPtr *secretEventCallbacks;
+ size_t nsecretEventCallbacks;
bool closeRegistered;
# if WITH_SASL
diff --git a/daemon/remote.c b/daemon/remote.c
index 3d837d8..3a7ee9e 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -236,6 +236,34 @@ remoteRelayNodeDeviceEventCheckACL(virNetServerClientPtr client,
}
static bool
+remoteRelaySecretEventCheckACL(virNetServerClientPtr client,
+ virConnectPtr conn,
+ virSecretPtr secret)
+{
+ virSecretDef def;
+ virIdentityPtr identity = NULL;
+ bool ret = false;
+
+ /* For now, we just create a virSecretDef with enough contents to
+ * satisfy what viraccessdriverpolkit.c references. This is a bit
+ * fragile, but I don't know of anything better. */
+ memcpy(def.uuid, secret->uuid, VIR_UUID_BUFLEN);
+ def.usage_type = secret->usageType;
+ def.usage_id = secret->usageID;
+
+ if (!(identity = virNetServerClientGetIdentity(client)))
+ goto cleanup;
+ if (virIdentitySetCurrent(identity) < 0)
+ goto cleanup;
+ ret = virConnectSecretEventRegisterAnyCheckACL(conn, &def);
+
+ cleanup:
+ ignore_value(virIdentitySetCurrent(NULL));
+ virObjectUnref(identity);
+ return ret;
+}
+
+static bool
remoteRelayDomainQemuMonitorEventCheckACL(virNetServerClientPtr client,
virConnectPtr conn, virDomainPtr dom)
{
@@ -1468,6 +1496,44 @@ static virConnectNodeDeviceEventGenericCallback
nodeDeviceEventCallbacks[] = {
verify(ARRAY_CARDINALITY(nodeDeviceEventCallbacks) == VIR_NODE_DEVICE_EVENT_ID_LAST);
+static int
+remoteRelaySecretEventLifecycle(virConnectPtr conn,
+ virSecretPtr secret,
+ int event,
+ int detail,
+ void *opaque)
+{
+ daemonClientEventCallbackPtr callback = opaque;
+ remote_secret_event_lifecycle_msg data;
+
+ if (callback->callbackID < 0 ||
+ !remoteRelaySecretEventCheckACL(callback->client, conn, secret))
+ return -1;
+
+ VIR_DEBUG("Relaying node secretice lifecycle event %d, detail %d, callback
%d",
+ event, detail, callback->callbackID);
+
+ /* build return data */
+ memset(&data, 0, sizeof(data));
+ make_nonnull_secret(&data.secret, secret);
+ data.callbackID = callback->callbackID;
+ data.event = event;
+ data.detail = detail;
+
+ remoteDispatchObjectEventSend(callback->client, remoteProgram,
+ REMOTE_PROC_SECRET_EVENT_LIFECYCLE,
+ (xdrproc_t)xdr_remote_secret_event_lifecycle_msg,
+ &data);
+
+ return 0;
+}
+
+static virConnectSecretEventGenericCallback secretEventCallbacks[] = {
+ VIR_SECRET_EVENT_CALLBACK(remoteRelaySecretEventLifecycle),
+};
+
+verify(ARRAY_CARDINALITY(secretEventCallbacks) == VIR_SECRET_EVENT_ID_LAST);
+
static void
remoteRelayDomainQemuMonitorEvent(virConnectPtr conn,
virDomainPtr dom,
@@ -1605,6 +1671,21 @@ void remoteClientFreeFunc(void *data)
}
VIR_FREE(priv->nodeDeviceEventCallbacks);
+ for (i = 0; i < priv->nsecretEventCallbacks; i++) {
+ int callbackID = priv->secretEventCallbacks[i]->callbackID;
+ if (callbackID < 0) {
+ VIR_WARN("unexpected incomplete secret callback %zu", i);
+ continue;
+ }
+ VIR_DEBUG("Deregistering remote secret event relay %d",
+ callbackID);
+ priv->secretEventCallbacks[i]->callbackID = -1;
+ if (virConnectSecretEventDeregisterAny(priv->conn,
+ callbackID) < 0)
+ VIR_WARN("unexpected secret event deregister failure");
+ }
+ VIR_FREE(priv->secretEventCallbacks);
+
for (i = 0; i < priv->nqemuEventCallbacks; i++) {
int callbackID = priv->qemuEventCallbacks[i]->callbackID;
if (callbackID < 0) {
@@ -5938,6 +6019,127 @@ remoteDispatchConnectNodeDeviceEventDeregisterAny(virNetServerPtr
server ATTRIBU
}
static int
+remoteDispatchConnectSecretEventRegisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
+ remote_connect_secret_event_register_any_args
*args,
+ remote_connect_secret_event_register_any_ret
*ret)
+{
+ int callbackID;
+ int rv = -1;
+ daemonClientEventCallbackPtr callback = NULL;
+ daemonClientEventCallbackPtr ref;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+ virSecretPtr secret = NULL;
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ if (args->secret &&
+ !(secret = get_nonnull_secret(priv->conn, *args->secret)))
+ goto cleanup;
+
+ if (args->eventID >= VIR_SECRET_EVENT_ID_LAST || args->eventID < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported secret event ID %d"), args->eventID);
+ goto cleanup;
+ }
+
+ /* If we call register first, we could append a complete callback
+ * to our array, but on OOM append failure, we'd have to then hope
+ * deregister works to undo our register. So instead we append an
+ * incomplete callback to our array, then register, then fix up
+ * our callback; but since VIR_APPEND_ELEMENT clears 'callback' on
+ * success, we use 'ref' to save a copy of the pointer. */
+ if (VIR_ALLOC(callback) < 0)
+ goto cleanup;
+ callback->client = client;
+ callback->eventID = args->eventID;
+ callback->callbackID = -1;
+ ref = callback;
+ if (VIR_APPEND_ELEMENT(priv->secretEventCallbacks,
+ priv->nsecretEventCallbacks,
+ callback) < 0)
+ goto cleanup;
+
+ if ((callbackID = virConnectSecretEventRegisterAny(priv->conn,
+ secret,
+ args->eventID,
+
secretEventCallbacks[args->eventID],
+ ref,
+ remoteEventCallbackFree)) < 0)
{
+ VIR_SHRINK_N(priv->secretEventCallbacks,
+ priv->nsecretEventCallbacks, 1);
+ callback = ref;
+ goto cleanup;
+ }
+
+ ref->callbackID = callbackID;
+ ret->callbackID = callbackID;
+
+ rv = 0;
+
+ cleanup:
+ VIR_FREE(callback);
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virObjectUnref(secret);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
+remoteDispatchConnectSecretEventDeregisterAny(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client,
+ virNetMessagePtr msg ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr
ATTRIBUTE_UNUSED,
+
remote_connect_secret_event_deregister_any_args *args)
+{
+ int rv = -1;
+ size_t i;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not
open"));
+ goto cleanup;
+ }
+
+ virMutexLock(&priv->lock);
+
+ for (i = 0; i < priv->nsecretEventCallbacks; i++) {
+ if (priv->secretEventCallbacks[i]->callbackID == args->callbackID)
+ break;
+ }
+ if (i == priv->nsecretEventCallbacks) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("node device event callback %d not registered"),
+ args->callbackID);
+ goto cleanup;
+ }
+
+ if (virConnectSecretEventDeregisterAny(priv->conn, args->callbackID) < 0)
+ goto cleanup;
+
+ VIR_DELETE_ELEMENT(priv->secretEventCallbacks, i,
+ priv->nsecretEventCallbacks);
+
+ rv = 0;
+
+ cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ virMutexUnlock(&priv->lock);
+ return rv;
+}
+
+static int
qemuDispatchConnectDomainMonitorEventRegister(virNetServerPtr server ATTRIBUTE_UNUSED,
virNetServerClientPtr client,
virNetMessagePtr msg ATTRIBUTE_UNUSED,
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index c161a56..e689316 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -36,6 +36,7 @@
#include "network_event.h"
#include "storage_event.h"
#include "node_device_event.h"
+#include "secret_event.h"
#include "driver.h"
#include "virbuffer.h"
#include "remote_driver.h"
@@ -385,6 +386,11 @@ remoteNodeDeviceBuildEventUpdate(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
void *evdata, void *opaque);
static void
+remoteSecretBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque);
+
+static void
remoteConnectNotifyEventConnectionClosed(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque);
@@ -583,6 +589,10 @@ static virNetClientProgramEvent remoteEvents[] = {
remoteNodeDeviceBuildEventUpdate,
sizeof(remote_node_device_event_update_msg),
(xdrproc_t)xdr_remote_node_device_event_update_msg },
+ { REMOTE_PROC_SECRET_EVENT_LIFECYCLE,
+ remoteSecretBuildEventLifecycle,
+ sizeof(remote_secret_event_lifecycle_msg),
+ (xdrproc_t)xdr_remote_secret_event_lifecycle_msg },
};
static void
@@ -3315,6 +3325,103 @@ remoteConnectNodeDeviceEventDeregisterAny(virConnectPtr conn,
static int
+remoteConnectSecretEventRegisterAny(virConnectPtr conn,
+ virSecretPtr secret,
+ int eventID,
+ virConnectSecretEventGenericCallback callback,
+ void *opaque,
+ virFreeCallback freecb)
+{
+ int rv = -1;
+ struct private_data *priv = conn->privateData;
+ remote_connect_secret_event_register_any_args args;
+ remote_connect_secret_event_register_any_ret ret;
+ int callbackID;
+ int count;
+ remote_nonnull_secret sec;
+
+ remoteDriverLock(priv);
+
+ if ((count = virSecretEventStateRegisterClient(conn, priv->eventState,
+ secret, eventID, callback,
+ opaque, freecb,
+ &callbackID)) < 0)
+ goto done;
+
+ /* If this is the first callback for this eventID, we need to enable
+ * events on the server */
+ if (count == 1) {
+ args.eventID = eventID;
+ if (secret) {
+ make_nonnull_secret(&sec, secret);
+ args.secret = &sec;
+ } else {
+ args.secret = NULL;
+ }
+
+ memset(&ret, 0, sizeof(ret));
+ if (call(conn, priv, 0, REMOTE_PROC_CONNECT_SECRET_EVENT_REGISTER_ANY,
+ (xdrproc_t) xdr_remote_connect_secret_event_register_any_args, (char *)
&args,
+ (xdrproc_t) xdr_remote_connect_secret_event_register_any_ret, (char *)
&ret) == -1) {
+ virObjectEventStateDeregisterID(conn, priv->eventState,
+ callbackID);
+ goto done;
+ }
+
+ virObjectEventStateSetRemote(conn, priv->eventState, callbackID,
+ ret.callbackID);
+ }
+
+ rv = callbackID;
+
+ done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
+static int
+remoteConnectSecretEventDeregisterAny(virConnectPtr conn,
+ int callbackID)
+{
+ struct private_data *priv = conn->privateData;
+ int rv = -1;
+ remote_connect_secret_event_deregister_any_args args;
+ int eventID;
+ int remoteID;
+ int count;
+
+ remoteDriverLock(priv);
+
+ if ((eventID = virObjectEventStateEventID(conn, priv->eventState,
+ callbackID, &remoteID)) < 0)
+ goto done;
+
+ if ((count = virObjectEventStateDeregisterID(conn, priv->eventState,
+ callbackID)) < 0)
+ goto done;
+
+ /* If that was the last callback for this eventID, we need to disable
+ * events on the server */
+ if (count == 0) {
+ args.callbackID = remoteID;
+
+ if (call(conn, priv, 0, REMOTE_PROC_CONNECT_SECRET_EVENT_DEREGISTER_ANY,
+ (xdrproc_t) xdr_remote_connect_secret_event_deregister_any_args, (char
*) &args,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
+ goto done;
+
+ }
+
+ rv = 0;
+
+ done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+
+static int
remoteConnectDomainQemuMonitorEventRegister(virConnectPtr conn,
virDomainPtr dom,
const char *event,
@@ -5388,6 +5495,28 @@ remoteNodeDeviceBuildEventUpdate(virNetClientProgramPtr prog
ATTRIBUTE_UNUSED,
}
static void
+remoteSecretBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
+{
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_secret_event_lifecycle_msg *msg = evdata;
+ virSecretPtr secret;
+ virObjectEventPtr event = NULL;
+
+ secret = get_nonnull_secret(conn, msg->secret);
+ if (!secret)
+ return;
+
+ event = virSecretEventLifecycleNew(secret->uuid, secret->usageType,
secret->usageID,
+ msg->event, msg->detail);
+ virObjectUnref(secret);
+
+ remoteEventQueue(priv, event, msg->callbackID);
+}
+
+static void
remoteDomainBuildQemuMonitorEvent(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
virNetClientPtr client ATTRIBUTE_UNUSED,
void *evdata, void *opaque)
@@ -8375,7 +8504,9 @@ static virSecretDriver secret_driver = {
.secretGetXMLDesc = remoteSecretGetXMLDesc, /* 0.7.1 */
.secretSetValue = remoteSecretSetValue, /* 0.7.1 */
.secretGetValue = remoteSecretGetValue, /* 0.7.1 */
- .secretUndefine = remoteSecretUndefine /* 0.7.1 */
+ .secretUndefine = remoteSecretUndefine, /* 0.7.1 */
+ .connectSecretEventDeregisterAny = remoteConnectSecretEventDeregisterAny, /* 3.0.0
*/
+ .connectSecretEventRegisterAny = remoteConnectSecretEventRegisterAny, /* 3.0.0 */
};
static virNodeDeviceDriver node_device_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index f268e1c..ce4c4ef 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -319,6 +319,7 @@ typedef remote_nonnull_nwfilter *remote_nwfilter;
typedef remote_nonnull_storage_pool *remote_storage_pool;
typedef remote_nonnull_storage_vol *remote_storage_vol;
typedef remote_nonnull_node_device *remote_node_device;
+typedef remote_nonnull_secret *remote_secret;
/* Error message. See <virterror.h> for explanation of fields. */
@@ -3360,6 +3361,26 @@ struct remote_domain_event_callback_metadata_change_msg {
remote_string nsuri;
};
+struct remote_connect_secret_event_register_any_args {
+ int eventID;
+ remote_secret secret;
+};
+
+struct remote_connect_secret_event_register_any_ret {
+ int callbackID;
+};
+
+struct remote_connect_secret_event_deregister_any_args {
+ int callbackID;
+};
+
+struct remote_secret_event_lifecycle_msg {
+ int callbackID;
+ remote_nonnull_secret secret;
+ int event;
+ int detail;
+};
+
/*----- Protocol. -----*/
/* Define the program number, protocol version and procedure numbers here. */
@@ -5965,5 +5986,27 @@ enum remote_procedure {
* @generate: both
* @acl: none
*/
- REMOTE_PROC_DOMAIN_EVENT_CALLBACK_METADATA_CHANGE = 379
+ REMOTE_PROC_DOMAIN_EVENT_CALLBACK_METADATA_CHANGE = 379,
+
+ /**
+ * @generate: none
+ * @priority: high
+ * @acl: connect:search_secrets
+ * @aclfilter: secret:getattr
+ */
+ REMOTE_PROC_CONNECT_SECRET_EVENT_REGISTER_ANY = 380,
+
+ /**
+ * @generate: none
+ * @priority: high
+ * @acl: connect:read
+ */
+ REMOTE_PROC_CONNECT_SECRET_EVENT_DEREGISTER_ANY = 381,
+
+ /**
+ * @generate: both
+ * @acl: none
+ */
+ REMOTE_PROC_SECRET_EVENT_LIFECYCLE = 382
+
};
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index 2fc9e46..0e8291a 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2806,6 +2806,22 @@ struct remote_domain_event_callback_metadata_change_msg {
int type;
remote_string nsuri
};
+struct remote_connect_secret_event_register_any_args {
+ int eventID;
+ remote_secret secret;
+};
+struct remote_connect_secret_event_register_any_ret {
+ int callbackID;
+};
+struct remote_connect_secret_event_deregister_any_args {
+ int callbackID;
+};
+struct remote_secret_event_lifecycle_msg {
+ int callbackID;
+ remote_nonnull_secret secret;
+ int event;
+ int detail;
+};
enum remote_procedure {
REMOTE_PROC_CONNECT_OPEN = 1,
REMOTE_PROC_CONNECT_CLOSE = 2,
@@ -3186,4 +3202,7 @@ enum remote_procedure {
REMOTE_PROC_NODE_DEVICE_EVENT_UPDATE = 377,
REMOTE_PROC_STORAGE_VOL_GET_INFO_FLAGS = 378,
REMOTE_PROC_DOMAIN_EVENT_CALLBACK_METADATA_CHANGE = 379,
+ REMOTE_PROC_CONNECT_SECRET_EVENT_REGISTER_ANY = 380,
+ REMOTE_PROC_CONNECT_SECRET_EVENT_DEREGISTER_ANY = 381,
+ REMOTE_PROC_SECRET_EVENT_LIFECYCLE = 382,
};
--
2.9.3