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