mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
remote: implement secret lifecycle event APIs
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
bd300b7194
commit
3b7bd6e540
@ -64,6 +64,8 @@ struct daemonClientPrivate {
|
||||
size_t nstorageEventCallbacks;
|
||||
daemonClientEventCallbackPtr *nodeDeviceEventCallbacks;
|
||||
size_t nnodeDeviceEventCallbacks;
|
||||
daemonClientEventCallbackPtr *secretEventCallbacks;
|
||||
size_t nsecretEventCallbacks;
|
||||
bool closeRegistered;
|
||||
|
||||
# if WITH_SASL
|
||||
|
202
daemon/remote.c
202
daemon/remote.c
@ -235,6 +235,34 @@ remoteRelayNodeDeviceEventCheckACL(virNetServerClientPtr client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -5937,6 +6018,127 @@ remoteDispatchConnectNodeDeviceEventDeregisterAny(virNetServerPtr server ATTRIBU
|
||||
return rv;
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -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"
|
||||
@ -384,6 +385,11 @@ remoteNodeDeviceBuildEventUpdate(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
|
||||
virNetClientPtr client 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,
|
||||
@ -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
|
||||
@ -3314,6 +3324,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,
|
||||
@ -5387,6 +5494,28 @@ remoteNodeDeviceBuildEventUpdate(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
|
||||
remoteEventQueue(priv, event, msg->callbackID);
|
||||
}
|
||||
|
||||
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,
|
||||
@ -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 = {
|
||||
|
@ -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
|
||||
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user