[libvirt] [PATCH v3 48/48] remote: pass identity across to newly opened daemons
Christophe de Dinechin
dinechin at redhat.com
Tue Jul 30 09:32:22 UTC 2019
Daniel P. Berrangé writes:
> When opening a connection to a second driver inside the daemon, we must
> ensure the identity of the current user is passed across. This allows
> the second daemon to perform access control checks against the real end
> users, instead of against the libvirt daemon that's proxying across the
> API calls.
>
> Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
> ---
> src/libvirt_remote.syms | 1 +
> src/remote/remote_daemon_dispatch.c | 110 +++++++++++++++++++++++++---
> src/remote/remote_driver.c | 1 +
> src/remote/remote_protocol.x | 18 ++++-
> src/remote_protocol-structs | 8 ++
> src/rpc/virnetserverclient.c | 12 +++
> src/rpc/virnetserverclient.h | 2 +
> 7 files changed, 140 insertions(+), 12 deletions(-)
>
> diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms
> index 3307d74324..0493467f46 100644
> --- a/src/libvirt_remote.syms
> +++ b/src/libvirt_remote.syms
> @@ -178,6 +178,7 @@ virNetServerClientSetAuthLocked;
> virNetServerClientSetAuthPendingLocked;
> virNetServerClientSetCloseHook;
> virNetServerClientSetDispatcher;
> +virNetServerClientSetIdentity;
> virNetServerClientSetQuietEOF;
> virNetServerClientSetReadonly;
> virNetServerClientStartKeepAlive;
> diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
> index 9ef76daa55..f828b75f3b 100644
> --- a/src/remote/remote_daemon_dispatch.c
> +++ b/src/remote/remote_daemon_dispatch.c
> @@ -51,6 +51,7 @@
> #include "virpolkit.h"
> #include "virthreadjob.h"
> #include "configmake.h"
> +#include "access/viraccessapicheck.h"
>
> #define VIR_FROM_THIS VIR_FROM_RPC
>
> @@ -1945,10 +1946,15 @@ static void remoteClientCloseFunc(virNetServerClientPtr client)
> static int
> remoteOpenConn(const char *uri,
> bool readonly,
> + bool preserveIdentity,
> virConnectPtr *conn)
> {
> - VIR_DEBUG("Getting secondary uri=%s readonly=%d conn=%p",
> - NULLSTR(uri), readonly, conn);
> + virTypedParameterPtr params = NULL;
> + int nparams = 0;
> +
> + VIR_DEBUG("Getting secondary uri=%s readonly=%d preserveIdent=%d conn=%p",
> + NULLSTR(uri), readonly, preserveIdentity, conn);
> +
> if (*conn)
> return 0;
>
> @@ -1957,15 +1963,42 @@ remoteOpenConn(const char *uri,
> return -1;
> }
>
> + if (preserveIdentity) {
> + VIR_AUTOUNREF(virIdentityPtr) ident = NULL;
> +
> + if (!(ident = virIdentityGetCurrent()))
> + return -1;
> +
> + if (virIdentityGetParameters(ident, ¶ms, &nparams) < 0)
> + goto error;
> + }
> +
> VIR_DEBUG("Opening driver %s", uri);
> if (readonly)
> *conn = virConnectOpenReadOnly(uri);
> else
> *conn = virConnectOpen(uri);
> if (!*conn)
> - return -1;
> + goto error;
> VIR_DEBUG("Opened driver %p", *conn);
> +
> + if (preserveIdentity) {
> + if (virConnectSetIdentity(*conn, params, nparams, 0) < 0)
> + goto error;
> +
> + virTypedParamsFree(params, nparams);
> + VIR_DEBUG("Forwarded current identity to secondary driver");
> + }
> +
> return 0;
> +
> + error:
> + virTypedParamsFree(params, nparams);
> + if (*conn) {
> + virConnectClose(*conn);
> + *conn = NULL;
> + }
> + return -1;
> }
>
>
> @@ -1992,6 +2025,7 @@ remoteGetInterfaceConn(virNetServerClientPtr client)
>
> if (remoteOpenConn(priv->interfaceURI,
> priv->readonly,
> + true,
> &priv->interfaceConn) < 0)
Consider adding a variable "preserveIdentity = true" and passing that
around to make it easier to read what that "true" is about?
> return NULL;
>
> @@ -2007,6 +2041,7 @@ remoteGetNetworkConn(virNetServerClientPtr client)
>
> if (remoteOpenConn(priv->networkURI,
> priv->readonly,
> + true,
> &priv->networkConn) < 0)
> return NULL;
>
> @@ -2022,6 +2057,7 @@ remoteGetNodeDevConn(virNetServerClientPtr client)
>
> if (remoteOpenConn(priv->nodedevURI,
> priv->readonly,
> + true,
> &priv->nodedevConn) < 0)
> return NULL;
>
> @@ -2037,6 +2073,7 @@ remoteGetNWFilterConn(virNetServerClientPtr client)
>
> if (remoteOpenConn(priv->nwfilterURI,
> priv->readonly,
> + true,
> &priv->nwfilterConn) < 0)
> return NULL;
>
> @@ -2052,6 +2089,7 @@ remoteGetSecretConn(virNetServerClientPtr client)
>
> if (remoteOpenConn(priv->secretURI,
> priv->readonly,
> + true,
> &priv->secretConn) < 0)
> return NULL;
>
> @@ -2067,6 +2105,7 @@ remoteGetStorageConn(virNetServerClientPtr client)
>
> if (remoteOpenConn(priv->storageURI,
> priv->readonly,
> + true,
> &priv->storageConn) < 0)
> return NULL;
>
> @@ -2235,6 +2274,7 @@ remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
> #ifndef LIBVIRTD
> const char *type = NULL;
> #endif
> + bool preserveIdentity = false;
>
> VIR_DEBUG("priv=%p conn=%p", priv, priv->conn);
> virMutexLock(&priv->lock);
> @@ -2264,14 +2304,16 @@ remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
> }
> #endif
>
> +#ifdef VIRTPROXYD
> + preserveIdentity = true;
> +#endif /* VIRTPROXYD */
> +
> VIR_DEBUG("Opening driver %s", name);
> - if (priv->readonly) {
> - if (!(priv->conn = virConnectOpenReadOnly(name)))
> - goto cleanup;
> - } else {
> - if (!(priv->conn = virConnectOpen(name)))
> - goto cleanup;
> - }
> + if (remoteOpenConn(name,
> + priv->readonly,
> + preserveIdentity,
> + &priv->conn) < 0)
> + goto cleanup;
> VIR_DEBUG("Opened %p", priv->conn);
>
> #ifndef LIBVIRTD
> @@ -2375,6 +2417,54 @@ remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,
> }
>
>
> +static int
> +remoteDispatchConnectSetIdentity(virNetServerPtr server ATTRIBUTE_UNUSED,
> + virNetServerClientPtr client,
> + virNetMessagePtr msg ATTRIBUTE_UNUSED,
> + virNetMessageErrorPtr rerr ATTRIBUTE_UNUSED,
Why ATTRIBUTE_UNUSED? Seems used in the cleanup?
> + remote_connect_set_identity_args *args)
> +{
> + virTypedParameterPtr params = NULL;
> + int nparams = 0;
> + int rv = -1;
> + virConnectPtr conn = remoteGetHypervisorConn(client);
> + virIdentityPtr ident = NULL;
(Trying to learn about coding style and conventions)
Why is this not autounref here? Is there a convention that if you
have explicit cleanup, you don't autounref?
> + if (!conn)
> + goto cleanup;
> +
> + VIR_DEBUG("Received forwarded identity");
> + if (virTypedParamsDeserialize((virTypedParameterRemotePtr) args->params.params_val,
> + args->params.params_len,
> + REMOTE_CONNECT_IDENTITY_PARAMS_MAX,
> + ¶ms,
> + &nparams) < 0)
> + goto cleanup;
Would it be useful to change the value rv over these cases,
and if rv < 0, add a VIR_DEBUG with its value? Or is there
sufficient debugging info from the individual calls already?
> +
> + VIR_TYPED_PARAMS_DEBUG(params, nparams);
> +
> + if (virConnectSetIdentityEnsureACL(conn) < 0)
> + goto cleanup;
> +
> + if (!(ident = virIdentityNew()))
> + goto cleanup;
> +
> + if (virIdentitySetParameters(ident, params, nparams) < 0)
> + goto cleanup;
> +
> + virNetServerClientSetIdentity(client, ident);
> +
> + rv = 0;
> +
> + cleanup:
> + virTypedParamsFree(params, nparams);
> + virObjectUnref(ident);
> + if (rv < 0)
> + virNetMessageSaveError(rerr);
> + return rv;
> +}
> +
> +
> +
> static int
> remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
> virNetServerClientPtr client,
> diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
> index 889d62ba4f..e2d2dc66be 100644
> --- a/src/remote/remote_driver.c
> +++ b/src/remote/remote_driver.c
> @@ -8510,6 +8510,7 @@ static virHypervisorDriver hypervisor_driver = {
> .name = "remote",
> .connectOpen = remoteConnectOpen, /* 0.3.0 */
> .connectClose = remoteConnectClose, /* 0.3.0 */
> + .connectSetIdentity = remoteConnectSetIdentity, /* 5.6.0 */
> .connectSupportsFeature = remoteConnectSupportsFeature, /* 0.3.0 */
> .connectGetType = remoteConnectGetType, /* 0.3.0 */
> .connectGetVersion = remoteConnectGetVersion, /* 0.3.0 */
> diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
> index 2f91bd1921..42e61ba20f 100644
> --- a/src/remote/remote_protocol.x
> +++ b/src/remote/remote_protocol.x
> @@ -53,6 +53,9 @@ typedef string remote_nonnull_string<REMOTE_STRING_MAX>;
> /* A long string, which may be NULL. */
> typedef remote_nonnull_string *remote_string;
>
> +/* Upper limit on identity parameters */
> +const REMOTE_CONNECT_IDENTITY_PARAMS_MAX = 20;
> +
> /* Upper limit on lists of domains. */
> const REMOTE_DOMAIN_LIST_MAX = 16384;
>
> @@ -3723,6 +3726,11 @@ struct remote_domain_checkpoint_delete_args {
> unsigned int flags;
> };
>
> +struct remote_connect_set_identity_args {
> + remote_typed_param params<REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX>;
> + unsigned int flags;
> +};
> +
> /*----- Protocol. -----*/
>
> /* Define the program number, protocol version and procedure numbers here. */
> @@ -6538,7 +6546,7 @@ enum remote_procedure {
> */
> REMOTE_PROC_NETWORK_PORT_DELETE = 410,
>
> - /**
> + /**
> * @generate: both
> * @acl: domain:checkpoint
> * @acl: domain:fs_freeze:VIR_DOMAIN_CHECKPOINT_CREATE_QUIESCE
> @@ -6584,5 +6592,11 @@ enum remote_procedure {
> * @generate: both
> * @acl: domain:checkpoint
> */
> - REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417
> + REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417,
> +
> + /**
> + * @generate: client
> + * @acl: connect:write
> + */
> + REMOTE_PROC_CONNECT_SET_IDENTITY = 418
> };
> diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
> index a42b4a9671..05229f00c5 100644
> --- a/src/remote_protocol-structs
> +++ b/src/remote_protocol-structs
> @@ -3105,6 +3105,13 @@ struct remote_domain_checkpoint_delete_args {
> remote_nonnull_domain_checkpoint checkpoint;
> u_int flags;
> };
> +struct remote_connect_set_identity_args {
> + struct {
> + u_int params_len;
> + remote_typed_param * params_val;
Indent by 8 spaces and try to align variables in the same file?
Nothing good could come out of it ;-)
> + } params;
> + u_int flags;
> +};
> enum remote_procedure {
> REMOTE_PROC_CONNECT_OPEN = 1,
> REMOTE_PROC_CONNECT_CLOSE = 2,
> @@ -3523,4 +3530,5 @@ enum remote_procedure {
> REMOTE_PROC_DOMAIN_CHECKPOINT_LOOKUP_BY_NAME = 415,
> REMOTE_PROC_DOMAIN_CHECKPOINT_GET_PARENT = 416,
> REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417,
> + REMOTE_PROC_CONNECT_SET_IDENTITY = 418,
> };
> diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c
> index 1f020a5a04..2a278171f5 100644
> --- a/src/rpc/virnetserverclient.c
> +++ b/src/rpc/virnetserverclient.c
> @@ -844,6 +844,18 @@ virIdentityPtr virNetServerClientGetIdentity(virNetServerClientPtr client)
> }
>
>
> +void virNetServerClientSetIdentity(virNetServerClientPtr client,
> + virIdentityPtr identity)
> +{
> + virObjectLock(client);
> + virObjectUnref(client->identity);
> + client->identity = identity;
> + if (client->identity)
> + virObjectRef(client->identity);
> + virObjectUnlock(client);
> +}
> +
> +
> int virNetServerClientGetSELinuxContext(virNetServerClientPtr client,
> char **context)
> {
> diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h
> index 1b01bedbcb..1c520fef6b 100644
> --- a/src/rpc/virnetserverclient.h
> +++ b/src/rpc/virnetserverclient.h
> @@ -123,6 +123,8 @@ int virNetServerClientGetSELinuxContext(virNetServerClientPtr client,
> char **context);
>
> virIdentityPtr virNetServerClientGetIdentity(virNetServerClientPtr client);
> +void virNetServerClientSetIdentity(virNetServerClientPtr client,
> + virIdentityPtr identity);
>
> void *virNetServerClientGetPrivateData(virNetServerClientPtr client);
>
> --
> 2.21.0
Reviewed-by: Christophe de Dinechin <dinechin at redhat.com>
--
Cheers,
Christophe de Dinechin (IRC c3d)
More information about the libvir-list
mailing list