[PATCH 2/6] virnetserver: Introduce virNetServerUpdateTlsFiles

Zhangbo (Oscar) oscar.zhangbo at huawei.com
Sun Feb 9 13:58:07 UTC 2020


Add an API to update server's tls context before admin method can be
introduced.
---
 include/libvirt/libvirt-admin.h |  8 ++++
 src/libvirt_remote.syms         |  1 +
 src/rpc/virnetserver.c          | 72 +++++++++++++++++++++++++++++++++
 src/rpc/virnetserver.h          |  3 ++
 src/rpc/virnetserverclient.c    |  4 ++
 src/rpc/virnettlscontext.c      | 41 +++++++++++++++++++
 src/rpc/virnettlscontext.h      |  2 +
 7 files changed, 131 insertions(+)

diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h
index abf2792926..3edc044490 100644
--- a/include/libvirt/libvirt-admin.h
+++ b/include/libvirt/libvirt-admin.h
@@ -392,6 +392,14 @@ int virAdmClientClose(virAdmClientPtr client, unsigned int flags);

 # define VIR_SERVER_CLIENTS_UNAUTH_CURRENT "nclients_unauth"

+/* tls related filetype flags. */
+typedef enum {
+    VIR_TLS_FILE_TYPE_CA_CERT             = (1U << 0),
+    VIR_TLS_FILE_TYPE_CA_CRL              = (1U << 1),
+    VIR_TLS_FILE_TYPE_SERVER_CERT         = (1U << 2),
+    VIR_TLS_FILE_TYPE_SERVER_KEY          = (1U << 3),
+} virServerTlsFiletype;
+
 int virAdmServerGetClientLimits(virAdmServerPtr srv,
                                 virTypedParameterPtr *params,
                                 int *nparams,
diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms
index 0493467f46..0018a0c41d 100644
--- a/src/libvirt_remote.syms
+++ b/src/libvirt_remote.syms
@@ -137,6 +137,7 @@ virNetServerSetClientLimits;
 virNetServerSetThreadPoolParameters;
 virNetServerSetTLSContext;
 virNetServerUpdateServices;
+virNetServerUpdateTlsFiles;


 # rpc/virnetserverclient.h
diff --git a/src/rpc/virnetserver.c b/src/rpc/virnetserver.c
index c87dade1a8..65ec677d0a 100644
--- a/src/rpc/virnetserver.c
+++ b/src/rpc/virnetserver.c
@@ -1207,3 +1207,75 @@ virNetServerSetClientLimits(virNetServerPtr srv,
     virObjectUnlock(srv);
     return ret;
 }
+
+static virNetTLSContextPtr
+virNetServerGetTLSContext(virNetServerPtr srv)
+{
+    size_t i;
+    virNetTLSContextPtr ctxt = NULL;
+    virNetServerServicePtr svc = NULL;
+
+    /* find svcTLS from srv, get svcTLS->tls */
+    for (i = 0; i < srv->nservices; i++) {
+        svc = srv->services[i];
+        ctxt = virNetServerServiceGetTLSContext(svc);
+        if (ctxt != NULL)
+            break;
+    }
+
+    return ctxt;
+}
+
+static int virNetServerUpdateTlsFilesCheckParams(unsigned int filetypes)
+{
+    bool haveSrvCert = filetypes & VIR_TLS_FILE_TYPE_SERVER_CERT;
+    bool haveSrvKey = filetypes & VIR_TLS_FILE_TYPE_SERVER_KEY;
+
+    if ((haveSrvCert && !haveSrvKey) ||
+        (!haveSrvCert && haveSrvKey)) {
+        virReportError(VIR_ERR_SYSTEM_ERROR,
+                       _("server cert/key must be updated together. "
+                       "filetypes: %d"), filetypes);
+        return -1;
+    }
+
+    return 0;
+}
+
+int
+virNetServerUpdateTlsFiles(virNetServerPtr srv,
+                           unsigned int filetypes)
+{
+    int ret = -1;
+#ifndef WITH_GNUTLS
+    virReportError(VIR_ERR_SYSTEM_ERROR,
+                   _("Don't support GNUTLS, can't to update filetypes: %d"),
+                   filetypes);
+#else
+    virNetTLSContextPtr ctxt = NULL;
+
+    if (virNetServerUpdateTlsFilesCheckParams(filetypes))
+        return -1;
+
+    virObjectLock(srv);
+
+    ctxt = virNetServerGetTLSContext(srv);
+    if (!ctxt) {
+        VIR_ERROR(_("no tls svc found, can't to update filetypes: %d"),
+                  filetypes);
+        goto cleanup;
+    }
+
+    if (virNetTLSContextReload(ctxt, filetypes)) {
+        VIR_ERROR(_("reload server's tls context fail"));
+        goto cleanup;
+    }
+
+    VIR_INFO("update all tls files complete, filetypes: %d", filetypes);
+    ret = 0;
+
+ cleanup:
+    virObjectUnlock(srv);
+#endif
+    return ret;
+}
diff --git a/src/rpc/virnetserver.h b/src/rpc/virnetserver.h
index 260c99b22d..99466dd041 100644
--- a/src/rpc/virnetserver.h
+++ b/src/rpc/virnetserver.h
@@ -133,3 +133,6 @@ size_t virNetServerGetCurrentUnauthClients(virNetServerPtr srv);
 int virNetServerSetClientLimits(virNetServerPtr srv,
                                 long long int maxClients,
                                 long long int maxClientsUnauth);
+
+int virNetServerUpdateTlsFiles(virNetServerPtr srv,
+                               unsigned int filetypes);
diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c
index 67b3bf9531..f0952cadde 100644
--- a/src/rpc/virnetserverclient.c
+++ b/src/rpc/virnetserverclient.c
@@ -1117,7 +1117,9 @@ int virNetServerClientInit(virNetServerClientPtr client)
                                   client->tls);

         /* Begin the TLS handshake. */
+        virObjectLock(client->tlsCtxt);
         ret = virNetTLSSessionHandshake(client->tls);
+        virObjectUnlock(client->tlsCtxt);
         if (ret == 0) {
             /* Unlikely, but ...  Next step is to check the certificate. */
             if (virNetServerClientCheckAccess(client) < 0)
@@ -1438,7 +1440,9 @@ virNetServerClientDispatchHandshake(virNetServerClientPtr client)
 {
     int ret;
     /* Continue the handshake. */
+    virObjectLock(client->tlsCtxt);
     ret = virNetTLSSessionHandshake(client->tls);
+    virObjectUnlock(client->tlsCtxt);
     if (ret == 0) {
         /* Finished.  Next step is to check the certificate. */
         if (virNetServerClientCheckAccess(client) < 0)
diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c
index 12811bed78..8baa6a15b2 100644
--- a/src/rpc/virnettlscontext.c
+++ b/src/rpc/virnettlscontext.c
@@ -1139,6 +1139,47 @@ void virNetTLSContextDispose(void *obj)
     gnutls_certificate_free_credentials(ctxt->x509cred);
 }

+int virNetTLSContextReload(virNetTLSContextPtr ctxt,
+                           unsigned int filetypes)
+{
+    int ret = -1;
+    char *cacert = NULL;
+    char *cacrl = NULL;
+    char *cert = NULL;
+    char *key = NULL;
+
+    virObjectLock(ctxt);
+
+    if (virNetTLSContextLocateCredentials(NULL, false, true,
+                                          &cacert, &cacrl, &cert, &key) < 0)
+        goto cleanup;
+
+    if (filetypes & VIR_TLS_FILE_TYPE_CA_CERT) {
+        if (virNetTLSContextSetCACert(ctxt, cacert, false))
+            goto cleanup;
+    }
+
+    if (filetypes & VIR_TLS_FILE_TYPE_CA_CRL) {
+        if (virNetTLSContextSetCACRL(ctxt, cacrl, false))
+            goto cleanup;
+    }
+
+    if (filetypes & VIR_TLS_FILE_TYPE_SERVER_CERT) {
+        gnutls_certificate_free_keys(ctxt->x509cred);
+        if (virNetTLSContextSetCertAndKey(ctxt, cert, key, false))
+            goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    virObjectUnlock(ctxt);
+    VIR_FREE(cacert);
+    VIR_FREE(cacrl);
+    VIR_FREE(key);
+    VIR_FREE(cert);
+    return ret;
+}

 static ssize_t
 virNetTLSSessionPush(void *opaque, const void *buf, size_t len)
diff --git a/src/rpc/virnettlscontext.h b/src/rpc/virnettlscontext.h
index f3273bc26a..9e83caf255 100644
--- a/src/rpc/virnettlscontext.h
+++ b/src/rpc/virnettlscontext.h
@@ -65,6 +65,8 @@ virNetTLSContextPtr virNetTLSContextNewClient(const char *cacert,
 int virNetTLSContextCheckCertificate(virNetTLSContextPtr ctxt,
                                      virNetTLSSessionPtr sess);

+int virNetTLSContextReload(virNetTLSContextPtr ctxt,
+                           unsigned int filetypes);

 typedef ssize_t (*virNetTLSSessionWriteFunc)(const char *buf, size_t len,
                                              void *opaque);
--
2.23.0.windows.1





More information about the libvir-list mailing list