]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
remote: pass identity across to newly opened daemons
authorDaniel P. Berrangé <berrange@redhat.com>
Fri, 26 Jul 2019 15:34:15 +0000 (16:34 +0100)
committerDaniel P. Berrangé <berrange@redhat.com>
Mon, 16 Sep 2019 10:25:53 +0000 (11:25 +0100)
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.

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
src/libvirt_remote.syms
src/remote/remote_daemon_dispatch.c
src/remote/remote_driver.c
src/remote/remote_protocol.x
src/remote_protocol-structs
src/rpc/virnetserverclient.c
src/rpc/virnetserverclient.h

index 3307d74324b96873162437c94fb32b3529122b94..0493467f460379d9d0219e85a8307454c482b184 100644 (file)
@@ -178,6 +178,7 @@ virNetServerClientSetAuthLocked;
 virNetServerClientSetAuthPendingLocked;
 virNetServerClientSetCloseHook;
 virNetServerClientSetDispatcher;
+virNetServerClientSetIdentity;
 virNetServerClientSetQuietEOF;
 virNetServerClientSetReadonly;
 virNetServerClientStartKeepAlive;
index ecde959088a3c99d8b5ffef19915d2043d39cdda..dbd2985c38980e01cbf8ebabda5473ab8b9e95a8 100644 (file)
@@ -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,16 @@ 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;
+    int ret = -1;
+
+    VIR_DEBUG("Getting secondary uri=%s readonly=%d preserveIdent=%d conn=%p",
+              NULLSTR(uri), readonly, preserveIdentity, conn);
+
     if (*conn)
         return 0;
 
@@ -1957,16 +1964,43 @@ remoteOpenConn(const char *uri,
         return -1;
     }
 
+    if (preserveIdentity) {
+        VIR_AUTOUNREF(virIdentityPtr) ident = NULL;
+
+        if (!(ident = virIdentityGetCurrent()))
+            return -1;
+
+        if (virIdentityGetParameters(ident, &params, &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);
 
-    return 0;
+    if (preserveIdentity) {
+        if (virConnectSetIdentity(*conn, params, nparams, 0) < 0)
+            goto error;
+
+        VIR_DEBUG("Forwarded current identity to secondary driver");
+    }
+
+    ret = 0;
+ cleanup:
+    virTypedParamsFree(params, nparams);
+    return ret;
+
+ error:
+    if (*conn) {
+        virConnectClose(*conn);
+        *conn = NULL;
+    }
+    goto cleanup;
 }
 
 
@@ -1993,6 +2027,7 @@ remoteGetInterfaceConn(virNetServerClientPtr client)
 
     if (remoteOpenConn(priv->interfaceURI,
                        priv->readonly,
+                       true,
                        &priv->interfaceConn) < 0)
         return NULL;
 
@@ -2008,6 +2043,7 @@ remoteGetNetworkConn(virNetServerClientPtr client)
 
     if (remoteOpenConn(priv->networkURI,
                        priv->readonly,
+                       true,
                        &priv->networkConn) < 0)
         return NULL;
 
@@ -2023,6 +2059,7 @@ remoteGetNodeDevConn(virNetServerClientPtr client)
 
     if (remoteOpenConn(priv->nodedevURI,
                        priv->readonly,
+                       true,
                        &priv->nodedevConn) < 0)
         return NULL;
 
@@ -2038,6 +2075,7 @@ remoteGetNWFilterConn(virNetServerClientPtr client)
 
     if (remoteOpenConn(priv->nwfilterURI,
                        priv->readonly,
+                       true,
                        &priv->nwfilterConn) < 0)
         return NULL;
 
@@ -2053,6 +2091,7 @@ remoteGetSecretConn(virNetServerClientPtr client)
 
     if (remoteOpenConn(priv->secretURI,
                        priv->readonly,
+                       true,
                        &priv->secretConn) < 0)
         return NULL;
 
@@ -2068,6 +2107,7 @@ remoteGetStorageConn(virNetServerClientPtr client)
 
     if (remoteOpenConn(priv->storageURI,
                        priv->readonly,
+                       true,
                        &priv->storageConn) < 0)
         return NULL;
 
@@ -2237,6 +2277,7 @@ remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
 #ifdef MODULE_NAME
     const char *type = NULL;
 #endif /* !MODULE_NAME */
+    bool preserveIdentity = false;
 
     VIR_DEBUG("priv=%p conn=%p", priv, priv->conn);
     virMutexLock(&priv->lock);
@@ -2264,16 +2305,16 @@ remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
 
         name = probeduri;
     }
-#endif
+
+    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);
 
 #ifdef MODULE_NAME
@@ -2384,6 +2425,53 @@ remoteDispatchConnectClose(virNetServerPtr server ATTRIBUTE_UNUSED,
 }
 
 
+static int
+remoteDispatchConnectSetIdentity(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                 virNetServerClientPtr client,
+                                 virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                                 virNetMessageErrorPtr rerr,
+                                 remote_connect_set_identity_args *args)
+{
+    virTypedParameterPtr params = NULL;
+    int nparams = 0;
+    int rv = -1;
+    virConnectPtr conn = remoteGetHypervisorConn(client);
+    VIR_AUTOUNREF(virIdentityPtr) ident = NULL;
+    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,
+                                  &params,
+                                  &nparams) < 0)
+        goto cleanup;
+
+    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);
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    return rv;
+}
+
+
+
 static int
 remoteDispatchDomainGetSchedulerType(virNetServerPtr server ATTRIBUTE_UNUSED,
                                      virNetServerClientPtr client,
index 2b86f5503581d0a90db1677a10acd6bd0fe1eb38..8789c5da00b751f747e19a2ba404b2d24b4ccd6b 100644 (file)
@@ -8507,6 +8507,7 @@ static virHypervisorDriver hypervisor_driver = {
     .name = "remote",
     .connectOpen = remoteConnectOpen, /* 0.3.0 */
     .connectClose = remoteConnectClose, /* 0.3.0 */
+    .connectSetIdentity = remoteConnectSetIdentity, /* 5.8.0 */
     .connectSupportsFeature = remoteConnectSupportsFeature, /* 0.3.0 */
     .connectGetType = remoteConnectGetType, /* 0.3.0 */
     .connectGetVersion = remoteConnectGetVersion, /* 0.3.0 */
index 75c2bc69ff24cdd78de265dca99f3cecde32719f..f4e3392212012849b3f1c47a43ecffd8199e837f 100644 (file)
@@ -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;
 
@@ -3736,6 +3739,11 @@ struct remote_domain_get_guest_info_ret {
     remote_typed_param params<REMOTE_DOMAIN_GUEST_INFO_PARAMS_MAX>;
 };
 
+struct remote_connect_set_identity_args {
+    remote_typed_param params<REMOTE_CONNECT_IDENTITY_PARAMS_MAX>;
+    unsigned int flags;
+};
+
 /*----- Protocol. -----*/
 
 /* Define the program number, protocol version and procedure numbers here. */
@@ -6603,5 +6611,11 @@ enum remote_procedure {
      * @generate: none
      * @acl: domain:write
      */
-    REMOTE_PROC_DOMAIN_GET_GUEST_INFO = 418
+    REMOTE_PROC_DOMAIN_GET_GUEST_INFO = 418,
+
+    /**
+     * @generate: client
+     * @acl: connect:write
+     */
+    REMOTE_PROC_CONNECT_SET_IDENTITY = 419
 };
index 616c3d5d529772c5c83aea6bc3969a894ce940a2..eb689b357405e0a33590ebcdbc2d806c27d3503f 100644 (file)
@@ -3116,6 +3116,13 @@ struct remote_domain_get_guest_info_ret {
                 remote_typed_param * params_val;
         } params;
 };
+struct remote_connect_set_identity_args {
+        struct {
+                u_int              params_len;
+                remote_typed_param * params_val;
+        } params;
+        u_int                      flags;
+};
 enum remote_procedure {
         REMOTE_PROC_CONNECT_OPEN = 1,
         REMOTE_PROC_CONNECT_CLOSE = 2,
@@ -3535,4 +3542,5 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_CHECKPOINT_GET_PARENT = 416,
         REMOTE_PROC_DOMAIN_CHECKPOINT_DELETE = 417,
         REMOTE_PROC_DOMAIN_GET_GUEST_INFO = 418,
+        REMOTE_PROC_CONNECT_SET_IDENTITY = 419,
 };
index 1b96d0339b50c8af0304b8d3cd39ac1be49119ea..171ee636dd5477ea5af9a5bfa22d3b086105d181 100644 (file)
@@ -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)
 {
index 1b01bedbcbffb3b57aa8c2d4891db7843d2a8078..1c520fef6bdff91abf865a2f7eae6bd650df26e2 100644 (file)
@@ -123,6 +123,8 @@ int virNetServerClientGetSELinuxContext(virNetServerClientPtr client,
                                         char **context);
 
 virIdentityPtr virNetServerClientGetIdentity(virNetServerClientPtr client);
+void virNetServerClientSetIdentity(virNetServerClientPtr client,
+                                   virIdentityPtr identity);
 
 void *virNetServerClientGetPrivateData(virNetServerClientPtr client);