[libvirt] [PATCH 5/9] remote: implement secret lifecycle event APIs

Daniel P. Berrange berrange at redhat.com
Thu Jan 5 13:59:23 UTC 2017


Signed-off-by: Daniel P. Berrange <berrange at 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




More information about the libvir-list mailing list