From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717771931857794.4392657461005; Fri, 7 Jun 2024 07:52:11 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 24FF5263F; Fri, 7 Jun 2024 10:52:10 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id C59C0262F; Fri, 7 Jun 2024 10:47:22 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 32E352595; Fri, 7 Jun 2024 10:47:16 -0400 (EDT) Received: from mx1.osci.io (polly.osci.io [8.43.85.229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 69C3B25FA for ; Fri, 7 Jun 2024 10:44:56 -0400 (EDT) Received: by mx1.osci.io (Postfix, from userid 994) id 564282254F; Fri, 7 Jun 2024 10:44:56 -0400 (EDT) Received: from mx3.osci.io (carla.osci.io [IPv6:2607:f0d0:1e02:35::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits)) (No client certificate requested) by mx1.osci.io (Postfix) with ESMTPS id 0CAF22236E for ; Fri, 7 Jun 2024 10:44:46 -0400 (EDT) Received: by mx3.osci.io (Postfix, from userid 990) id 0DF8430721D8; Fri, 7 Jun 2024 09:33:00 -0500 (CDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by mx3.osci.io (Postfix) with ESMTPS id 4A14830721D2 for ; Fri, 7 Jun 2024 09:32:58 -0500 (CDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-101-C_9FUbipPrS_yULVF59T6g-1; Fri, 07 Jun 2024 10:26:18 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8988B185A783 for ; Fri, 7 Jun 2024 14:26:18 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id D53BE492BC6; Fri, 7 Jun 2024 14:26:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770383; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EeoGMepXA+1EGeAFXpb0X3JgXBWfWLs4onN1h4UFqGs=; b=fmWASeXdaHKF0t2SflxnYBwgf9ho6Pl88IVSzd330jT/LJM2h6fUyMfO0rsoJOlCsbjz1S ZHO9bCdZqv5cXc20WT03pA5X27Bq+CxZtrbnfuHuVO2ts63Tjta+w3JQZnzYNtXQrXJY5i EjM5z1YzA6m7rZdFlpjxh2vFQnd2AmQ= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770512; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EeoGMepXA+1EGeAFXpb0X3JgXBWfWLs4onN1h4UFqGs=; b=WYklAA+t8+EXUJE7xLE9c7wq32da3JqM7c2iC15VdspTIEKR1jt5HCSQY0TPt/G/wXR/1U IlIZgftnmNe0S/Ufr4tUeAj+YPxmj8B6D2TvOuL1BDxQaxrqiajKzqBX4Ra2ajNBf3Q/fw V+QqcjmRxBZ6urQQhA3DYAzIQTxxDtc= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770643; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EeoGMepXA+1EGeAFXpb0X3JgXBWfWLs4onN1h4UFqGs=; b=ETVeR2m+ZxykNO/JEqEwvc5vYKgqoYc08PWwxcZf2psBu1dRbuvbWG50p4khJtJ1ANY0ZC BaFvIkjb2ED4ok3QNh/bEhd4owQKcyDBuY+tW6y/CweJUxQ/F5I2HCsUZJP0rtv5emRyx8 IFvHLioGONDninrq7APsBJKt6oyGzgU= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770776; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EeoGMepXA+1EGeAFXpb0X3JgXBWfWLs4onN1h4UFqGs=; b=MdiXaks2FNMlBFZYVT2NTIZDMkD0omuTLKc2loA5mn6ea+PRBME3qXGcQi2a1s7Q0jm1EQ Wy6cpMjmWq5LPR8ObaAr2Yagost2tUSPsU12KysCMmHvZlBCnWn5ZaVHXKjMSv6rwtyomR n7evyARWoodNk34yTZNOoqb0Lh618xg= X-MC-Unique: C_9FUbipPrS_yULVF59T6g-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 1/9] rpc: split out helpers for TLS cert path location Date: Fri, 7 Jun 2024 15:26:08 +0100 Message-ID: <20240607142616.749339-2-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: V3ZGYIICNAWFCT4BCN3FZKAYRGDH5PBT X-Message-ID-Hash: V3ZGYIICNAWFCT4BCN3FZKAYRGDH5PBT X-MailFrom: SRS0=RZ0v=NJ=redhat.com=berrange@osci.io X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (found 4 invalid signatures) X-ZM-MESSAGEID: 1717771932902100001 Content-Type: text/plain; charset="utf-8" We'll want to access these paths from outside the TLS context code, so split them into a standalone file. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- src/rpc/meson.build | 6 +- src/rpc/virnettlsconfig.c | 202 +++++++++++++++++++++++++++++++++++++ src/rpc/virnettlsconfig.h | 68 +++++++++++++ src/rpc/virnettlscontext.c | 70 ++----------- 4 files changed, 285 insertions(+), 61 deletions(-) create mode 100644 src/rpc/virnettlsconfig.c create mode 100644 src/rpc/virnettlsconfig.h diff --git a/src/rpc/meson.build b/src/rpc/meson.build index 9d98bc6259..d11d532d0f 100644 --- a/src/rpc/meson.build +++ b/src/rpc/meson.build @@ -1,6 +1,10 @@ gendispatch_prog =3D find_program('gendispatch.pl') =20 -socket_sources =3D [ +tlsconfig_sources =3D [ + files('virnettlsconfig.c'), +] + +socket_sources =3D tlsconfig_sources + [ 'virnettlscontext.c', 'virnetsocket.c', ] diff --git a/src/rpc/virnettlsconfig.c b/src/rpc/virnettlsconfig.c new file mode 100644 index 0000000000..d020083d6a --- /dev/null +++ b/src/rpc/virnettlsconfig.c @@ -0,0 +1,202 @@ +/* + * virnettlsconfig.c: TLS x509 configuration helpers + * + * Copyright (C) 2010-2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include "virnettlsconfig.h" +#include "virlog.h" +#include "virutil.h" + +#define VIR_FROM_THIS VIR_FROM_RPC + +VIR_LOG_INIT("rpc.nettlscontext"); + +char *virNetTLSConfigUserPKIBaseDir(void) +{ + g_autofree char *userdir =3D virGetUserDirectory(); + + return g_strdup_printf("%s/.pki/libvirt", userdir); +} + +static void virNetTLSConfigTrust(const char *cacertdir, + const char *cacrldir, + char **cacert, + char **cacrl) +{ + if (!*cacert) + *cacert =3D g_strdup_printf("%s/%s", cacertdir, "cacert.pem"); + if (!*cacrl) + *cacrl =3D g_strdup_printf("%s/%s", cacrldir, "cacrl.pem"); + + VIR_DEBUG("TLS CA cert %s", *cacert); + VIR_DEBUG("TLS CA CRL %s", *cacrl); +} + +static void virNetTLSConfigIdentity(int isServer, + const char *certdir, + const char *keydir, + char **cert, + char **key) +{ + if (!*key) + *key =3D g_strdup_printf("%s/%s", keydir, + isServer ? "serverkey.pem" : "clientkey.pem= "); + if (!*cert) + *cert =3D g_strdup_printf("%s/%s", certdir, + isServer ? "servercert.pem" : "clientcert.= pem"); + + VIR_DEBUG("TLS key %s", *key); + VIR_DEBUG("TLS cert %s", *cert); +} + +void virNetTLSConfigCustomTrust(const char *pkipath, + char **cacert, + char **cacrl) +{ + VIR_DEBUG("Locating trust chain in custom dir %s", pkipath); + virNetTLSConfigTrust(pkipath, + pkipath, + cacert, + cacrl); +} + +void virNetTLSConfigUserTrust(char **cacert, + char **cacrl) +{ + g_autofree char *pkipath =3D virNetTLSConfigUserPKIBaseDir(); + + VIR_DEBUG("Locating trust chain in user dir %s", pkipath); + + virNetTLSConfigTrust(pkipath, + pkipath, + cacert, + cacrl); +} + +void virNetTLSConfigSystemTrust(char **cacert, + char **cacrl) +{ + VIR_DEBUG("Locating trust chain in system dir %s", LIBVIRT_PKI_DIR); + + virNetTLSConfigTrust(LIBVIRT_CACERT_DIR, + LIBVIRT_CACRL_DIR, + cacert, + cacrl); +} + +void virNetTLSConfigCustomIdentity(const char *pkipath, + int isServer, + char **cert, + char **key) +{ + VIR_DEBUG("Locating creds in custom dir %s", pkipath); + virNetTLSConfigIdentity(isServer, + pkipath, + pkipath, + cert, + key); +} + +void virNetTLSConfigUserIdentity(int isServer, + char **cert, + char **key) +{ + g_autofree char *pkipath =3D virNetTLSConfigUserPKIBaseDir(); + + VIR_DEBUG("Locating creds in user dir %s", pkipath); + + virNetTLSConfigIdentity(isServer, + pkipath, + pkipath, + cert, + key); +} + +void virNetTLSConfigSystemIdentity(int isServer, + char **cert, + char **key) +{ + VIR_DEBUG("Locating creds in system dir %s", LIBVIRT_PKI_DIR); + + virNetTLSConfigIdentity(isServer, + LIBVIRT_CERT_DIR, + LIBVIRT_KEY_DIR, + cert, + key); +} + +void virNetTLSConfigCustomCreds(const char *pkipath, + int isServer, + char **cacert, + char **cacrl, + char **cert, + char **key) +{ + VIR_DEBUG("Locating creds in custom dir %s", pkipath); + virNetTLSConfigTrust(pkipath, + pkipath, + cacert, + cacrl); + virNetTLSConfigIdentity(isServer, + pkipath, + pkipath, + cert, + key); +} + +void virNetTLSConfigUserCreds(int isServer, + char **cacert, + char **cacrl, + char **cert, + char **key) +{ + g_autofree char *pkipath =3D virNetTLSConfigUserPKIBaseDir(); + + VIR_DEBUG("Locating creds in user dir %s", pkipath); + + virNetTLSConfigTrust(pkipath, + pkipath, + cacert, + cacrl); + virNetTLSConfigIdentity(isServer, + pkipath, + pkipath, + cert, + key); +} + +void virNetTLSConfigSystemCreds(int isServer, + char **cacert, + char **cacrl, + char **cert, + char **key) +{ + VIR_DEBUG("Locating creds in system dir %s", LIBVIRT_PKI_DIR); + + virNetTLSConfigTrust(LIBVIRT_CACERT_DIR, + LIBVIRT_CACRL_DIR, + cacert, + cacrl); + virNetTLSConfigIdentity(isServer, + LIBVIRT_CERT_DIR, + LIBVIRT_KEY_DIR, + cert, + key); +} diff --git a/src/rpc/virnettlsconfig.h b/src/rpc/virnettlsconfig.h new file mode 100644 index 0000000000..797b3e3ac5 --- /dev/null +++ b/src/rpc/virnettlsconfig.h @@ -0,0 +1,68 @@ +/* + * virnettlsconfig.h: TLS x509 configuration helpers + * + * Copyright (C) 2010-2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#pragma once + +#include "configmake.h" + +#define LIBVIRT_PKI_DIR SYSCONFDIR "/pki" +#define LIBVIRT_CACERT_DIR LIBVIRT_PKI_DIR "/CA" +#define LIBVIRT_CACRL_DIR LIBVIRT_PKI_DIR "/CA" +#define LIBVIRT_KEY_DIR LIBVIRT_PKI_DIR "/libvirt/private" +#define LIBVIRT_CERT_DIR LIBVIRT_PKI_DIR "/libvirt" + +char *virNetTLSConfigUserPKIBaseDir(void); + +void virNetTLSConfigCustomTrust(const char *pkipath, + char **cacert, + char **cacrl); +void virNetTLSConfigUserTrust(char **cacert, + char **cacrl); +void virNetTLSConfigSystemTrust(char **cacert, + char **cacrl); + +void virNetTLSConfigCustomIdentity(const char *pkipath, + int isServer, + char **cert, + char **key); +void virNetTLSConfigUserIdentity(int isServer, + char **cert, + char **key); +void virNetTLSConfigSystemIdentity(int isServer, + char **cert, + char **key); + + +void virNetTLSConfigCustomCreds(const char *pkipath, + int isServer, + char **cacert, + char **cacrl, + char **cert, + char **key); +void virNetTLSConfigUserCreds(int isServer, + char **cacert, + char **cacrl, + char **cert, + char **key); +void virNetTLSConfigSystemCreds(int isServer, + char **cacert, + char **cacrl, + char **cert, + char **key); diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index dc60244927..4223043bc9 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -27,6 +27,7 @@ #include =20 #include "virnettlscontext.h" +#include "virnettlsconfig.h" #include "virstring.h" =20 #include "viralloc.h" @@ -36,15 +37,6 @@ #include "virlog.h" #include "virprobe.h" #include "virthread.h" -#include "configmake.h" - -#define LIBVIRT_PKI_DIR SYSCONFDIR "/pki" -#define LIBVIRT_CACERT LIBVIRT_PKI_DIR "/CA/cacert.pem" -#define LIBVIRT_CACRL LIBVIRT_PKI_DIR "/CA/cacrl.pem" -#define LIBVIRT_CLIENTKEY LIBVIRT_PKI_DIR "/libvirt/private/clientkey.pem" -#define LIBVIRT_CLIENTCERT LIBVIRT_PKI_DIR "/libvirt/clientcert.pem" -#define LIBVIRT_SERVERKEY LIBVIRT_PKI_DIR "/libvirt/private/serverkey.pem" -#define LIBVIRT_SERVERCERT LIBVIRT_PKI_DIR "/libvirt/servercert.pem" =20 #define VIR_FROM_THIS VIR_FROM_RPC =20 @@ -721,9 +713,6 @@ static int virNetTLSContextLocateCredentials(const char= *pkipath, char **cert, char **key) { - char *userdir =3D NULL; - char *user_pki_path =3D NULL; - *cacert =3D NULL; *cacrl =3D NULL; *key =3D NULL; @@ -736,33 +725,13 @@ static int virNetTLSContextLocateCredentials(const ch= ar *pkipath, * files actually exist there */ if (pkipath) { - VIR_DEBUG("Told to use TLS credentials in %s", pkipath); - *cacert =3D g_strdup_printf("%s/%s", pkipath, "cacert.pem"); - *cacrl =3D g_strdup_printf("%s/%s", pkipath, "cacrl.pem"); - *key =3D g_strdup_printf("%s/%s", pkipath, - isServer ? "serverkey.pem" : "clientkey.pem= "); - - *cert =3D g_strdup_printf("%s/%s", pkipath, - isServer ? "servercert.pem" : "clientcert.= pem"); + virNetTLSConfigCustomCreds(pkipath, isServer, + cacert, cacrl, + cert, key); } else if (tryUserPkiPath) { - /* Check to see if $HOME/.pki contains at least one of the - * files and if so, use that - */ - userdir =3D virGetUserDirectory(); - - user_pki_path =3D g_strdup_printf("%s/.pki/libvirt", userdir); - - VIR_DEBUG("Trying to find TLS user credentials in %s", user_pki_pa= th); - - *cacert =3D g_strdup_printf("%s/%s", user_pki_path, "cacert.pem"); - - *cacrl =3D g_strdup_printf("%s/%s", user_pki_path, "cacrl.pem"); - - *key =3D g_strdup_printf("%s/%s", user_pki_path, - isServer ? "serverkey.pem" : "clientkey.pem= "); - - *cert =3D g_strdup_printf("%s/%s", user_pki_path, - isServer ? "servercert.pem" : "clientcert.= pem"); + virNetTLSConfigUserCreds(isServer, + cacert, cacrl, + cert, key); =20 /* * If some of the files can't be found, fallback @@ -782,28 +751,9 @@ static int virNetTLSContextLocateCredentials(const cha= r *pkipath, } } =20 - /* No explicit path, or user path didn't exist, so - * fallback to global defaults - */ - if (!*cacert) { - VIR_DEBUG("Using default TLS CA certificate path"); - *cacert =3D g_strdup(LIBVIRT_CACERT); - } - - if (!*cacrl) { - VIR_DEBUG("Using default TLS CA revocation list path"); - *cacrl =3D g_strdup(LIBVIRT_CACRL); - } - - if (!*key && !*cert) { - VIR_DEBUG("Using default TLS key/certificate path"); - *key =3D g_strdup(isServer ? LIBVIRT_SERVERKEY : LIBVIRT_CLIENTKEY= ); - - *cert =3D g_strdup(isServer ? LIBVIRT_SERVERCERT : LIBVIRT_CLIENTC= ERT); - } - - VIR_FREE(user_pki_path); - VIR_FREE(userdir); + virNetTLSConfigSystemCreds(isServer, + cacert, cacrl, + cert, key); =20 return 0; } --=20 2.43.0 From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717771590208995.9022986038011; Fri, 7 Jun 2024 07:46:30 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 4B7F52545; Fri, 7 Jun 2024 10:46:28 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 6C1BE260D; Fri, 7 Jun 2024 10:43:05 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id BB0122602; Fri, 7 Jun 2024 10:42:58 -0400 (EDT) Received: from mx1.osci.io (polly.osci.io [8.43.85.229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 769E02621 for ; Fri, 7 Jun 2024 10:40:25 -0400 (EDT) Received: by mx1.osci.io (Postfix, from userid 994) id 7C10A2236E; Fri, 7 Jun 2024 10:40:24 -0400 (EDT) Received: from mx3.osci.io (carla.osci.io [IPv6:2607:f0d0:1e02:35::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits)) (No client certificate requested) by mx1.osci.io (Postfix) with ESMTPS id E43BF2254F for ; Fri, 7 Jun 2024 10:40:15 -0400 (EDT) Received: by mx3.osci.io (Postfix, from userid 990) id 49FCF30721D5; Fri, 7 Jun 2024 09:32:55 -0500 (CDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by mx3.osci.io (Postfix) with ESMTPS id B575530721D1 for ; Fri, 7 Jun 2024 09:32:53 -0500 (CDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-77-bAnFEtftOGi0jEKfSHktDg-1; Fri, 07 Jun 2024 10:26:19 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 412A1811E79 for ; Fri, 7 Jun 2024 14:26:19 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id BEC25492BC6; Fri, 7 Jun 2024 14:26:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770382; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=smT8ANyVuM9il1EIloSa7zTDcIMeh51A3YC7t8ummW4=; b=D+o/fhE063PeDI2Y3jzU/JexhjMv+TTkxa1gaQkwWLRsXI9MXLJz08fKSrxuRUvnQXCC2L LaK7RxnwDug6lm1CRHv09YrJR0Cy1dfk4ceI1EMlYAfKmFkQ1ziV6dPSV6DlafaIZgqSVP XsvVUlbeWib5VxPVaoTDMtIw+Gw6R9Q= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770510; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=smT8ANyVuM9il1EIloSa7zTDcIMeh51A3YC7t8ummW4=; b=VZbNaMg9f9tU3Cw21vBWsBlQIKJcpOHXS8YbPIVmReMevld1X4cZGpgx1Krc8D/9J6pFsF 4UATOApPMIgafwNKhRoefWzEf4kSN1mjgN0ERJqWzqpyXrUT8obgaI5u2/TBHyWnNoeFaB saodr/r8mMFFYPeGBCGtF9NDfaNj8mw= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770642; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=smT8ANyVuM9il1EIloSa7zTDcIMeh51A3YC7t8ummW4=; b=f/hXTNUKcnFgk7mAbmhPTy5S1mcEScN/dgXKHu9QxYtk/mx5cHF8ebuWMmVPsfHcDE6IHd KP4SR3mJxmwO/Ib721/lLYwYM+3UzthwiwLowuTuI07ulQpbNRcdrLVWwNBT0smAG+QqsA L8xAfI4iAHEeCxMfZZ/AA040OXTQaBc= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770773; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=smT8ANyVuM9il1EIloSa7zTDcIMeh51A3YC7t8ummW4=; b=KXZYHAEsfl/1AHuDoxmMimUCME/KzWEE5y7mNT+er8NXbduuDt7Pms5IqRQTQqj26P0B1L E7uW0VivCvOzPJ/jgbItdMzabWX/kCcDHsrMMFvHq8DF8nGlzGWwV27Mer1uPY2WetvVZs 1+YYs85ho6Bs2bNq+fCv1zL8/PKvk1E= X-MC-Unique: bAnFEtftOGi0jEKfSHktDg-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 2/9] rpc: refactor method for checking session certificates Date: Fri, 7 Jun 2024 15:26:09 +0100 Message-ID: <20240607142616.749339-3-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: IEWPFTFQR2VCN3XY3BW2Z2FT4GMACSWN X-Message-ID-Hash: IEWPFTFQR2VCN3XY3BW2Z2FT4GMACSWN X-MailFrom: SRS0=RZ0v=NJ=redhat.com=berrange@osci.io X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (found 4 invalid signatures) X-ZM-MESSAGEID: 1717771591104100001 Content-Type: text/plain; charset="utf-8" This will facilitate moving much of the code into a new file in the subsequent commit. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- src/rpc/virnettlscontext.c | 109 ++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 43 deletions(-) diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index 4223043bc9..a56abee009 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -876,6 +876,65 @@ virNetTLSContext *virNetTLSContextNewClient(const char= *cacert, sanityCheckCert, requireValidCert, false); } =20 +static int virNetTLSContextCertValidateCA(gnutls_x509_crt_t cert, + bool isServer) +{ + if (virNetTLSContextCheckCertTimes(cert, "[session]", isServer, true) = < 0) + return -1; + + return 0; +} + +static char *virNetTLSContextCertValidate(gnutls_x509_crt_t cert, + bool isServer, + const char *hostname, + const char *const *x509dnACL) +{ + size_t dnamesize =3D 256; + g_autofree char *dname =3D g_new0(char, dnamesize); + int ret; + + if (virNetTLSContextCheckCertTimes(cert, "[session]", + isServer, false) < 0) + return NULL; + + ret =3D gnutls_x509_crt_get_dn(cert, dname, &dnamesize); + if (ret =3D=3D GNUTLS_E_SHORT_MEMORY_BUFFER) { + VIR_DEBUG("Reallocating dname to fit %zu bytes", dnamesize); + dname =3D g_realloc(dname, dnamesize); + ret =3D gnutls_x509_crt_get_dn(cert, dname, &dnamesize); + } + if (ret !=3D 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Failed to get certificate %1$s distinguished nam= e: %2$s"), + "[session]", gnutls_strerror(ret)); + return NULL; + } + + VIR_DEBUG("Peer DN is %s", dname); + + if (virNetTLSContextCheckCertDN(cert, "[session]", hostname, + dname, x509dnACL) < 0) + return NULL; + + /* !isServer, since on the client, we're validating the + * server's cert, and on the server, the client's cert + */ + if (virNetTLSContextCheckCertBasicConstraints(cert, "[session]", + !isServer, false) < 0) + return NULL; + + if (virNetTLSContextCheckCertKeyUsage(cert, "[session]", + false) < 0) + return NULL; + + /* !isServer - as above */ + if (virNetTLSContextCheckCertKeyPurpose(cert, "[session]", + !isServer) < 0) + return NULL; + + return g_steal_pointer(&dname); +} =20 static int virNetTLSContextValidCertificate(virNetTLSContext *ctxt, virNetTLSSession *sess) @@ -945,57 +1004,21 @@ static int virNetTLSContextValidCertificate(virNetTL= SContext *ctxt, goto authfail; } =20 - if (virNetTLSContextCheckCertTimes(cert, "[session]", - sess->isServer, i > 0) < 0) { - gnutls_x509_crt_deinit(cert); - goto authdeny; - } - if (i =3D=3D 0) { - ret =3D gnutls_x509_crt_get_dn(cert, dname, &dnamesize); - if (ret =3D=3D GNUTLS_E_SHORT_MEMORY_BUFFER) { - VIR_DEBUG("Reallocating dname to fit %zu bytes", dnamesize= ); - dname =3D g_realloc(dname, dnamesize); - dnameptr =3D dname; - ret =3D gnutls_x509_crt_get_dn(cert, dname, &dnamesize); - } - if (ret !=3D 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Failed to get certificate %1$s distingui= shed name: %2$s"), - "[session]", gnutls_strerror(ret)); - goto authfail; - } - sess->x509dname =3D g_steal_pointer(&dname); - VIR_DEBUG("Peer DN is %s", dnameptr); - - if (virNetTLSContextCheckCertDN(cert, "[session]", sess->hostn= ame, - dnameptr, ctxt->x509dnACL) < 0= ) { - gnutls_x509_crt_deinit(cert); - goto authdeny; - } - - /* !sess->isServer, since on the client, we're validating the - * server's cert, and on the server, the client's cert - */ - if (virNetTLSContextCheckCertBasicConstraints(cert, "[session]= ", - !sess->isServer,= false) < 0) { - gnutls_x509_crt_deinit(cert); - goto authdeny; - } - - if (virNetTLSContextCheckCertKeyUsage(cert, "[session]", - false) < 0) { + if (!(sess->x509dname =3D virNetTLSContextCertValidate(cert, + sess->isS= erver, + sess->hos= tname, + ctxt->x50= 9dnACL))) { gnutls_x509_crt_deinit(cert); goto authdeny; } - - /* !sess->isServer - as above */ - if (virNetTLSContextCheckCertKeyPurpose(cert, "[session]", - !sess->isServer) < 0) { + } else { + if (virNetTLSContextCertValidateCA(cert, sess->isServer) < 0) { gnutls_x509_crt_deinit(cert); goto authdeny; } } + gnutls_x509_crt_deinit(cert); } =20 --=20 2.43.0 From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717770569998856.3828236383986; Fri, 7 Jun 2024 07:29:29 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id D33612385; Fri, 7 Jun 2024 10:29:24 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 36ED32341; Fri, 7 Jun 2024 10:26:32 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 0851C2378; Fri, 7 Jun 2024 10:26:29 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id C59C922F5 for ; Fri, 7 Jun 2024 10:26:23 -0400 (EDT) Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-646-Ra5h2QBNPZmMZ3jOLfNDuw-1; Fri, 07 Jun 2024 10:26:20 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4887F1C05129 for ; Fri, 7 Jun 2024 14:26:20 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id 820A9492BC6; Fri, 7 Jun 2024 14:26:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770382; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AC2xbQ1VhLU2TE7NIblnO5b7PMrtxQZ491I5fl8C6bc=; b=I6EX3An6I8F/yugDCk9x/QD6pEDGzkQJ8fBKc/uyaQd/jM+GukX3i5GKlH8cKwOONkcGP3 BlI4bgUbOSBLOxHWuYQE5TVdmItmZTZ33UV5B5Bq1I28KEJSwcNiLOxeE0igWkTOlVYnyj SPER5/6QoLyWZ4zp4LzA07b0CPSFbps= X-MC-Unique: Ra5h2QBNPZmMZ3jOLfNDuw-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 3/9] rpc: split TLS cert validation into separate file Date: Fri, 7 Jun 2024 15:26:10 +0100 Message-ID: <20240607142616.749339-4-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: D5ALL3WUXMIEKOMGR4EJMIVJZF3HXZLP X-Message-ID-Hash: D5ALL3WUXMIEKOMGR4EJMIVJZF3HXZLP X-MailFrom: berrange@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1717770572436100001 Content-Type: text/plain; charset="utf-8" The TLS cert validation logic will be reused for the new impl of the virt-pki-validate tool. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- po/POTFILES | 1 + src/rpc/meson.build | 1 + src/rpc/virnettlscert.c | 553 +++++++++++++++++++++++++++++++++++++ src/rpc/virnettlscert.h | 42 +++ src/rpc/virnettlscontext.c | 535 +---------------------------------- 5 files changed, 606 insertions(+), 526 deletions(-) create mode 100644 src/rpc/virnettlscert.c create mode 100644 src/rpc/virnettlscert.h diff --git a/po/POTFILES b/po/POTFILES index 4ad7e19e08..0f68c652eb 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -219,6 +219,7 @@ src/rpc/virnetserverprogram.c src/rpc/virnetserverservice.c src/rpc/virnetsocket.c src/rpc/virnetsshsession.c +src/rpc/virnettlscert.c src/rpc/virnettlscontext.c src/secret/secret_driver.c src/security/security_apparmor.c diff --git a/src/rpc/meson.build b/src/rpc/meson.build index d11d532d0f..8bdbf5c88f 100644 --- a/src/rpc/meson.build +++ b/src/rpc/meson.build @@ -2,6 +2,7 @@ gendispatch_prog =3D find_program('gendispatch.pl') =20 tlsconfig_sources =3D [ files('virnettlsconfig.c'), + files('virnettlscert.c'), ] =20 socket_sources =3D tlsconfig_sources + [ diff --git a/src/rpc/virnettlscert.c b/src/rpc/virnettlscert.c new file mode 100644 index 0000000000..2e1e4c56d5 --- /dev/null +++ b/src/rpc/virnettlscert.c @@ -0,0 +1,553 @@ +/* + * virnettlscert.c: TLS x509 certificate helpers + * + * Copyright (C) 2010-2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#include + +#include "virnettlscert.h" + +#include "viralloc.h" +#include "virfile.h" +#include "virlog.h" +#include "virerror.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("rpc.nettlscert"); + +static int virNetTLSCertCheckTimes(gnutls_x509_crt_t cert, + const char *certFile, + bool isServer, + bool isCA) +{ + time_t now; + + if ((now =3D time(NULL)) =3D=3D ((time_t)-1)) { + virReportSystemError(errno, "%s", + _("cannot get current time")); + return -1; + } + + if (gnutls_x509_crt_get_expiration_time(cert) < now) { + virReportError(VIR_ERR_SYSTEM_ERROR, + (isCA ? + _("The CA certificate %1$s has expired") : + (isServer ? + _("The server certificate %1$s has expired") : + _("The client certificate %1$s has expired"))), + certFile); + return -1; + } + + if (gnutls_x509_crt_get_activation_time(cert) > now) { + virReportError(VIR_ERR_SYSTEM_ERROR, + (isCA ? + _("The CA certificate %1$s is not yet active") : + (isServer ? + _("The server certificate %1$s is not yet active"= ) : + _("The client certificate %1$s is not yet active"= ))), + certFile); + return -1; + } + + return 0; +} + + +static int virNetTLSCertCheckBasicConstraints(gnutls_x509_crt_t cert, + const char *certFile, + bool isServer, + bool isCA) +{ + int status; + + status =3D gnutls_x509_crt_get_basic_constraints(cert, NULL, NULL, NUL= L); + VIR_DEBUG("Cert %s basic constraints %d", certFile, status); + + if (status > 0) { /* It is a CA cert */ + if (!isCA) { + virReportError(VIR_ERR_SYSTEM_ERROR, isServer ? + _("The certificate %1$s basic constraints show = a CA, but we need one for a server") : + _("The certificate %1$s basic constraints show = a CA, but we need one for a client"), + certFile); + return -1; + } + } else if (status =3D=3D 0) { /* It is not a CA cert */ + if (isCA) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("The certificate %1$s basic constraints do no= t show a CA"), + certFile); + return -1; + } + } else if (status =3D=3D GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { /* M= issing basicConstraints */ + if (isCA) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("The certificate %1$s is missing basic constr= aints for a CA"), + certFile); + return -1; + } + } else { /* General error */ + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Unable to query certificate %1$s basic constrain= ts %2$s"), + certFile, gnutls_strerror(status)); + return -1; + } + + return 0; +} + + +static int virNetTLSCertCheckKeyUsage(gnutls_x509_crt_t cert, + const char *certFile, + bool isCA) +{ + int status; + unsigned int usage =3D 0; + unsigned int critical =3D 0; + + status =3D gnutls_x509_crt_get_key_usage(cert, &usage, &critical); + + VIR_DEBUG("Cert %s key usage status %d usage %d critical %u", certFile= , status, usage, critical); + if (status < 0) { + if (status =3D=3D GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + usage =3D isCA ? GNUTLS_KEY_KEY_CERT_SIGN : + GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT; + } else { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Unable to query certificate %1$s key usage %= 2$s"), + certFile, gnutls_strerror(status)); + return -1; + } + } + + if (isCA) { + if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) { + if (critical) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Certificate %1$s usage does not permit c= ertificate signing"), + certFile); + return -1; + } else { + VIR_WARN("Certificate %s usage does not permit certificate= signing", + certFile); + } + } + } else { + if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { + if (critical) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Certificate %1$s usage does not permit d= igital signature"), + certFile); + return -1; + } else { + VIR_WARN("Certificate %s usage does not permit digital sig= nature", + certFile); + } + } + if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) { + if (critical) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Certificate %1$s usage does not permit k= ey encipherment"), + certFile); + return -1; + } else { + VIR_WARN("Certificate %s usage does not permit key enciphe= rment", + certFile); + } + } + } + + return 0; +} + + +static int virNetTLSCertCheckKeyPurpose(gnutls_x509_crt_t cert, + const char *certFile, + bool isServer) +{ + int status; + size_t i; + unsigned int purposeCritical; + unsigned int critical; + char *buffer =3D NULL; + size_t size; + bool allowClient =3D false, allowServer =3D false; + + critical =3D 0; + for (i =3D 0; ; i++) { + size =3D 0; + status =3D gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer, &s= ize, NULL); + + if (status =3D=3D GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + VIR_DEBUG("No key purpose data available at slot %zu", i); + + /* If there is no data at all, then we must allow client/serve= r to pass */ + if (i =3D=3D 0) + allowServer =3D allowClient =3D true; + break; + } + if (status !=3D GNUTLS_E_SHORT_MEMORY_BUFFER) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Unable to query certificate %1$s key purpose= %2$s"), + certFile, gnutls_strerror(status)); + return -1; + } + + buffer =3D g_new0(char, size); + status =3D gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer, &s= ize, &purposeCritical); + if (status < 0) { + VIR_FREE(buffer); + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Unable to query certificate %1$s key purpose= %2$s"), + certFile, gnutls_strerror(status)); + return -1; + } + if (purposeCritical) + critical =3D true; + + VIR_DEBUG("Key purpose %d %s critical %u", status, buffer, purpose= Critical); + if (STREQ(buffer, GNUTLS_KP_TLS_WWW_SERVER)) { + allowServer =3D true; + } else if (STREQ(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) { + allowClient =3D true; + } else if (STRNEQ(buffer, GNUTLS_KP_ANY)) { + allowServer =3D allowClient =3D true; + } + + VIR_FREE(buffer); + } + + if (isServer) { + if (!allowServer) { + if (critical) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Certificate %1$s purpose does not allow = use for with a TLS server"), + certFile); + return -1; + } else { + VIR_WARN("Certificate %s purpose does not allow use for wi= th a TLS server", + certFile); + } + } + } else { + if (!allowClient) { + if (critical) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Certificate %1$s purpose does not allow = use for with a TLS client"), + certFile); + return -1; + } else { + VIR_WARN("Certificate %s purpose does not allow use for wi= th a TLS client", + certFile); + } + } + } + + return 0; +} + +/* Check DN is on tls_allowed_dn_list. */ +static int +virNetTLSCertCheckDNACL(const char *dname, + const char *const *wildcards) +{ + while (*wildcards) { + if (g_pattern_match_simple(*wildcards, dname)) + return 1; + + wildcards++; + } + + /* Log the client's DN for debugging */ + VIR_DEBUG("Failed ACL check for client DN '%s'", dname); + + /* This is the most common error: make it informative. */ + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("Client's Distinguished Name is not on the list of al= lowed clients (tls_allowed_dn_list). Use 'virt-pki-query-dn clientcert.pem= ' to view the Distinguished Name field in the client certificate, or run th= is daemon with --verbose option.")); + return 0; +} + + +static int +virNetTLSCertCheckDN(gnutls_x509_crt_t cert, + const char *certFile, + const char *hostname, + const char *dname, + const char *const *acl) +{ + if (acl && dname && + virNetTLSCertCheckDNACL(dname, acl) <=3D 0) + return -1; + + if (hostname && + !gnutls_x509_crt_check_hostname(cert, hostname)) { + virReportError(VIR_ERR_RPC, + _("Certificate %1$s owner does not match the hostna= me %2$s"), + certFile, hostname); + return -1; + } + + return 0; +} + + +static int virNetTLSCertCheck(gnutls_x509_crt_t cert, + const char *certFile, + bool isServer, + bool isCA) +{ + if (virNetTLSCertCheckTimes(cert, certFile, isServer, isCA) < 0) + return -1; + + if (virNetTLSCertCheckBasicConstraints(cert, certFile, isServer, isCA)= < 0) + return -1; + + if (virNetTLSCertCheckKeyUsage(cert, certFile, isCA) < 0) + return -1; + + if (!isCA && + virNetTLSCertCheckKeyPurpose(cert, certFile, isServer) < 0) + return -1; + + return 0; +} + + +static int virNetTLSCertCheckPair(gnutls_x509_crt_t cert, + const char *certFile, + gnutls_x509_crt_t *cacerts, + size_t ncacerts, + const char *cacertFile, + bool isServer) +{ + unsigned int status; + + if (gnutls_x509_crt_list_verify(&cert, 1, + cacerts, ncacerts, + NULL, 0, + 0, &status) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, isServer ? + _("Unable to verify server certificate %1$s against= CA certificate %2$s") : + _("Unable to verify client certificate %1$s against= CA certificate %2$s"), + certFile, cacertFile); + return -1; + } + + if (status !=3D 0) { + const char *reason =3D _("Invalid certificate"); + + if (status & GNUTLS_CERT_INVALID) + reason =3D _("The certificate is not trusted."); + + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) + reason =3D _("The certificate hasn't got a known issuer."); + + if (status & GNUTLS_CERT_REVOKED) + reason =3D _("The certificate has been revoked."); + + if (status & GNUTLS_CERT_INSECURE_ALGORITHM) + reason =3D _("The certificate uses an insecure algorithm"); + + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Our own certificate %1$s failed validation again= st %2$s: %3$s"), + certFile, cacertFile, reason); + return -1; + } + + return 0; +} + + +gnutls_x509_crt_t virNetTLSCertLoadFromFile(const char *certFile, + bool isServer) +{ + gnutls_datum_t data; + gnutls_x509_crt_t cert =3D NULL; + g_autofree char *buf =3D NULL; + int ret =3D -1; + + VIR_DEBUG("isServer %d certFile %s", + isServer, certFile); + + if (gnutls_x509_crt_init(&cert) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, "%s", + _("Unable to initialize certificate")); + goto cleanup; + } + + if (virFileReadAll(certFile, (1<<16), &buf) < 0) + goto cleanup; + + data.data =3D (unsigned char *)buf; + data.size =3D strlen(buf); + + if (gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, isServer ? + _("Unable to import server certificate %1$s") : + _("Unable to import client certificate %1$s"), + certFile); + goto cleanup; + } + + ret =3D 0; + + cleanup: + if (ret !=3D 0) { + g_clear_pointer(&cert, gnutls_x509_crt_deinit); + } + return cert; +} + + +static int virNetTLSCertLoadCAListFromFile(const char *certFile, + gnutls_x509_crt_t *certs, + unsigned int certMax, + size_t *ncerts) +{ + gnutls_datum_t data; + g_autofree char *buf =3D NULL; + + *ncerts =3D 0; + VIR_DEBUG("certFile %s", certFile); + + if (virFileReadAll(certFile, (1<<16), &buf) < 0) + return -1; + + data.data =3D (unsigned char *)buf; + data.size =3D strlen(buf); + + if (gnutls_x509_crt_list_import(certs, &certMax, &data, GNUTLS_X509_FM= T_PEM, 0) < 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Unable to import CA certificate list %1$s"), + certFile); + return -1; + } + *ncerts =3D certMax; + + return 0; +} + + +#define MAX_CERTS 16 +int virNetTLSCertSanityCheck(bool isServer, + const char *cacertFile, + const char *certFile) +{ + gnutls_x509_crt_t cert =3D NULL; + gnutls_x509_crt_t cacerts[MAX_CERTS] =3D { 0 }; + size_t ncacerts =3D 0; + size_t i; + int ret =3D -1; + + if ((access(certFile, R_OK) =3D=3D 0) && + !(cert =3D virNetTLSCertLoadFromFile(certFile, isServer))) + goto cleanup; + if ((access(cacertFile, R_OK) =3D=3D 0) && + virNetTLSCertLoadCAListFromFile(cacertFile, cacerts, + MAX_CERTS, &ncacerts) < 0) + goto cleanup; + + if (cert && + virNetTLSCertCheck(cert, certFile, isServer, false) < 0) + goto cleanup; + + for (i =3D 0; i < ncacerts; i++) { + if (virNetTLSCertCheck(cacerts[i], cacertFile, isServer, true) < 0) + goto cleanup; + } + + if (cert && ncacerts && + virNetTLSCertCheckPair(cert, certFile, cacerts, ncacerts, cacertFi= le, isServer) < 0) + goto cleanup; + + ret =3D 0; + + cleanup: + if (cert) + gnutls_x509_crt_deinit(cert); + for (i =3D 0; i < ncacerts; i++) + gnutls_x509_crt_deinit(cacerts[i]); + return ret; +} + +int virNetTLSCertValidateCA(gnutls_x509_crt_t cert, + bool isServer) +{ + if (virNetTLSCertCheckTimes(cert, "[session]", + isServer, true) < 0) { + return -1; + } + return 0; +} + +char *virNetTLSCertValidate(gnutls_x509_crt_t cert, + bool isServer, + const char *hostname, + const char *const *x509dnACL) +{ + size_t dnamesize =3D 256; + g_autofree char *dname =3D g_new0(char, dnamesize); + int ret; + + if (virNetTLSCertCheckTimes(cert, "[session]", + isServer, false) < 0) { + return NULL; + } + + ret =3D gnutls_x509_crt_get_dn(cert, dname, &dnamesize); + if (ret =3D=3D GNUTLS_E_SHORT_MEMORY_BUFFER) { + VIR_DEBUG("Reallocating dname to fit %zu bytes", dnamesize); + dname =3D g_realloc(dname, dnamesize); + ret =3D gnutls_x509_crt_get_dn(cert, dname, &dnamesize); + } + if (ret !=3D 0) { + virReportError(VIR_ERR_SYSTEM_ERROR, + _("Failed to get certificate %1$s distinguished nam= e: %2$s"), + "[session]", gnutls_strerror(ret)); + return NULL; + } + + VIR_DEBUG("Peer DN is %s", dname); + + if (virNetTLSCertCheckDN(cert, "[session]", hostname, + dname, x509dnACL) < 0) { + return NULL; + } + + /* !isServer, since on the client, we're validating the + * server's cert, and on the server, the client's cert + */ + if (virNetTLSCertCheckBasicConstraints(cert, "[session]", + !isServer, false) < 0) { + return NULL; + } + + if (virNetTLSCertCheckKeyUsage(cert, "[session]", + false) < 0) { + return NULL; + } + + /* !isServer - as above */ + if (virNetTLSCertCheckKeyPurpose(cert, "[session]", + !isServer) < 0) { + return NULL; + } + + return g_steal_pointer(&dname); +} diff --git a/src/rpc/virnettlscert.h b/src/rpc/virnettlscert.h new file mode 100644 index 0000000000..0ac511a141 --- /dev/null +++ b/src/rpc/virnettlscert.h @@ -0,0 +1,42 @@ +/* + * virnettlscert.h: TLS x509 certificate helpers + * + * Copyright (C) 2010-2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + */ + +#pragma once + +#include +#include +#include + +#include "internal.h" + +int virNetTLSCertSanityCheck(bool isServer, + const char *cacertFile, + const char *certFile); + +int virNetTLSCertValidateCA(gnutls_x509_crt_t cert, + bool isServer); + +char *virNetTLSCertValidate(gnutls_x509_crt_t cert, + bool isServer, + const char *hostname, + const char *const *x509dnACL); + +gnutls_x509_crt_t virNetTLSCertLoadFromFile(const char *certFile, + bool isServer); diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c index a56abee009..e8023133b4 100644 --- a/src/rpc/virnettlscontext.c +++ b/src/rpc/virnettlscontext.c @@ -28,6 +28,7 @@ =20 #include "virnettlscontext.h" #include "virnettlsconfig.h" +#include "virnettlscert.h" #include "virstring.h" =20 #include "viralloc.h" @@ -110,466 +111,6 @@ static void virNetTLSLog(int level G_GNUC_UNUSED, } =20 =20 -static int virNetTLSContextCheckCertTimes(gnutls_x509_crt_t cert, - const char *certFile, - bool isServer, - bool isCA) -{ - time_t now; - - if ((now =3D time(NULL)) =3D=3D ((time_t)-1)) { - virReportSystemError(errno, "%s", - _("cannot get current time")); - return -1; - } - - if (gnutls_x509_crt_get_expiration_time(cert) < now) { - virReportError(VIR_ERR_SYSTEM_ERROR, - (isCA ? - _("The CA certificate %1$s has expired") : - (isServer ? - _("The server certificate %1$s has expired") : - _("The client certificate %1$s has expired"))), - certFile); - return -1; - } - - if (gnutls_x509_crt_get_activation_time(cert) > now) { - virReportError(VIR_ERR_SYSTEM_ERROR, - (isCA ? - _("The CA certificate %1$s is not yet active") : - (isServer ? - _("The server certificate %1$s is not yet active"= ) : - _("The client certificate %1$s is not yet active"= ))), - certFile); - return -1; - } - - return 0; -} - - -static int virNetTLSContextCheckCertBasicConstraints(gnutls_x509_crt_t cer= t, - const char *certFile, - bool isServer, - bool isCA) -{ - int status; - - status =3D gnutls_x509_crt_get_basic_constraints(cert, NULL, NULL, NUL= L); - VIR_DEBUG("Cert %s basic constraints %d", certFile, status); - - if (status > 0) { /* It is a CA cert */ - if (!isCA) { - virReportError(VIR_ERR_SYSTEM_ERROR, isServer ? - _("The certificate %1$s basic constraints show = a CA, but we need one for a server") : - _("The certificate %1$s basic constraints show = a CA, but we need one for a client"), - certFile); - return -1; - } - } else if (status =3D=3D 0) { /* It is not a CA cert */ - if (isCA) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("The certificate %1$s basic constraints do no= t show a CA"), - certFile); - return -1; - } - } else if (status =3D=3D GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { /* M= issing basicConstraints */ - if (isCA) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("The certificate %1$s is missing basic constr= aints for a CA"), - certFile); - return -1; - } - } else { /* General error */ - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Unable to query certificate %1$s basic constrain= ts %2$s"), - certFile, gnutls_strerror(status)); - return -1; - } - - return 0; -} - - -static int virNetTLSContextCheckCertKeyUsage(gnutls_x509_crt_t cert, - const char *certFile, - bool isCA) -{ - int status; - unsigned int usage =3D 0; - unsigned int critical =3D 0; - - status =3D gnutls_x509_crt_get_key_usage(cert, &usage, &critical); - - VIR_DEBUG("Cert %s key usage status %d usage %d critical %u", certFile= , status, usage, critical); - if (status < 0) { - if (status =3D=3D GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - usage =3D isCA ? GNUTLS_KEY_KEY_CERT_SIGN : - GNUTLS_KEY_DIGITAL_SIGNATURE|GNUTLS_KEY_KEY_ENCIPHERMENT; - } else { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Unable to query certificate %1$s key usage %= 2$s"), - certFile, gnutls_strerror(status)); - return -1; - } - } - - if (isCA) { - if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) { - if (critical) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Certificate %1$s usage does not permit c= ertificate signing"), - certFile); - return -1; - } else { - VIR_WARN("Certificate %s usage does not permit certificate= signing", - certFile); - } - } - } else { - if (!(usage & GNUTLS_KEY_DIGITAL_SIGNATURE)) { - if (critical) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Certificate %1$s usage does not permit d= igital signature"), - certFile); - return -1; - } else { - VIR_WARN("Certificate %s usage does not permit digital sig= nature", - certFile); - } - } - if (!(usage & GNUTLS_KEY_KEY_ENCIPHERMENT)) { - if (critical) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Certificate %1$s usage does not permit k= ey encipherment"), - certFile); - return -1; - } else { - VIR_WARN("Certificate %s usage does not permit key enciphe= rment", - certFile); - } - } - } - - return 0; -} - - -static int virNetTLSContextCheckCertKeyPurpose(gnutls_x509_crt_t cert, - const char *certFile, - bool isServer) -{ - int status; - size_t i; - unsigned int purposeCritical; - unsigned int critical; - char *buffer =3D NULL; - size_t size; - bool allowClient =3D false, allowServer =3D false; - - critical =3D 0; - for (i =3D 0; ; i++) { - size =3D 0; - status =3D gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer, &s= ize, NULL); - - if (status =3D=3D GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - VIR_DEBUG("No key purpose data available at slot %zu", i); - - /* If there is no data at all, then we must allow client/serve= r to pass */ - if (i =3D=3D 0) - allowServer =3D allowClient =3D true; - break; - } - if (status !=3D GNUTLS_E_SHORT_MEMORY_BUFFER) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Unable to query certificate %1$s key purpose= %2$s"), - certFile, gnutls_strerror(status)); - return -1; - } - - buffer =3D g_new0(char, size); - status =3D gnutls_x509_crt_get_key_purpose_oid(cert, i, buffer, &s= ize, &purposeCritical); - if (status < 0) { - VIR_FREE(buffer); - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Unable to query certificate %1$s key purpose= %2$s"), - certFile, gnutls_strerror(status)); - return -1; - } - if (purposeCritical) - critical =3D true; - - VIR_DEBUG("Key purpose %d %s critical %u", status, buffer, purpose= Critical); - if (STREQ(buffer, GNUTLS_KP_TLS_WWW_SERVER)) { - allowServer =3D true; - } else if (STREQ(buffer, GNUTLS_KP_TLS_WWW_CLIENT)) { - allowClient =3D true; - } else if (STRNEQ(buffer, GNUTLS_KP_ANY)) { - allowServer =3D allowClient =3D true; - } - - VIR_FREE(buffer); - } - - if (isServer) { - if (!allowServer) { - if (critical) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Certificate %1$s purpose does not allow = use for with a TLS server"), - certFile); - return -1; - } else { - VIR_WARN("Certificate %s purpose does not allow use for wi= th a TLS server", - certFile); - } - } - } else { - if (!allowClient) { - if (critical) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Certificate %1$s purpose does not allow = use for with a TLS client"), - certFile); - return -1; - } else { - VIR_WARN("Certificate %s purpose does not allow use for wi= th a TLS client", - certFile); - } - } - } - - return 0; -} - -/* Check DN is on tls_allowed_dn_list. */ -static int -virNetTLSContextCheckCertDNACL(const char *dname, - const char *const *wildcards) -{ - while (*wildcards) { - if (g_pattern_match_simple(*wildcards, dname)) - return 1; - - wildcards++; - } - - /* Log the client's DN for debugging */ - VIR_DEBUG("Failed ACL check for client DN '%s'", dname); - - /* This is the most common error: make it informative. */ - virReportError(VIR_ERR_SYSTEM_ERROR, "%s", - _("Client's Distinguished Name is not on the list of al= lowed clients (tls_allowed_dn_list). Use 'virt-pki-query-dn clientcert.pem= ' to view the Distinguished Name field in the client certificate, or run th= is daemon with --verbose option.")); - return 0; -} - - -static int -virNetTLSContextCheckCertDN(gnutls_x509_crt_t cert, - const char *certFile, - const char *hostname, - const char *dname, - const char *const *acl) -{ - if (acl && dname && - virNetTLSContextCheckCertDNACL(dname, acl) <=3D 0) - return -1; - - if (hostname && - !gnutls_x509_crt_check_hostname(cert, hostname)) { - virReportError(VIR_ERR_RPC, - _("Certificate %1$s owner does not match the hostna= me %2$s"), - certFile, hostname); - return -1; - } - - return 0; -} - - -static int virNetTLSContextCheckCert(gnutls_x509_crt_t cert, - const char *certFile, - bool isServer, - bool isCA) -{ - if (virNetTLSContextCheckCertTimes(cert, certFile, - isServer, isCA) < 0) - return -1; - - if (virNetTLSContextCheckCertBasicConstraints(cert, certFile, - isServer, isCA) < 0) - return -1; - - if (virNetTLSContextCheckCertKeyUsage(cert, certFile, - isCA) < 0) - return -1; - - if (!isCA && - virNetTLSContextCheckCertKeyPurpose(cert, certFile, - isServer) < 0) - return -1; - - return 0; -} - - -static int virNetTLSContextCheckCertPair(gnutls_x509_crt_t cert, - const char *certFile, - gnutls_x509_crt_t *cacerts, - size_t ncacerts, - const char *cacertFile, - bool isServer) -{ - unsigned int status; - - if (gnutls_x509_crt_list_verify(&cert, 1, - cacerts, ncacerts, - NULL, 0, - 0, &status) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, isServer ? - _("Unable to verify server certificate %1$s against= CA certificate %2$s") : - _("Unable to verify client certificate %1$s against= CA certificate %2$s"), - certFile, cacertFile); - return -1; - } - - if (status !=3D 0) { - const char *reason =3D _("Invalid certificate"); - - if (status & GNUTLS_CERT_INVALID) - reason =3D _("The certificate is not trusted."); - - if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) - reason =3D _("The certificate hasn't got a known issuer."); - - if (status & GNUTLS_CERT_REVOKED) - reason =3D _("The certificate has been revoked."); - - if (status & GNUTLS_CERT_INSECURE_ALGORITHM) - reason =3D _("The certificate uses an insecure algorithm"); - - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Our own certificate %1$s failed validation again= st %2$s: %3$s"), - certFile, cacertFile, reason); - return -1; - } - - return 0; -} - - -static gnutls_x509_crt_t virNetTLSContextLoadCertFromFile(const char *cert= File, - bool isServer) -{ - gnutls_datum_t data; - gnutls_x509_crt_t cert =3D NULL; - g_autofree char *buf =3D NULL; - int ret =3D -1; - - VIR_DEBUG("isServer %d certFile %s", - isServer, certFile); - - if (gnutls_x509_crt_init(&cert) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, "%s", - _("Unable to initialize certificate")); - goto cleanup; - } - - if (virFileReadAll(certFile, (1<<16), &buf) < 0) - goto cleanup; - - data.data =3D (unsigned char *)buf; - data.size =3D strlen(buf); - - if (gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_PEM) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, isServer ? - _("Unable to import server certificate %1$s") : - _("Unable to import client certificate %1$s"), - certFile); - goto cleanup; - } - - ret =3D 0; - - cleanup: - if (ret !=3D 0) { - g_clear_pointer(&cert, gnutls_x509_crt_deinit); - } - return cert; -} - - -static int virNetTLSContextLoadCACertListFromFile(const char *certFile, - gnutls_x509_crt_t *certs, - unsigned int certMax, - size_t *ncerts) -{ - gnutls_datum_t data; - g_autofree char *buf =3D NULL; - - *ncerts =3D 0; - VIR_DEBUG("certFile %s", certFile); - - if (virFileReadAll(certFile, (1<<16), &buf) < 0) - return -1; - - data.data =3D (unsigned char *)buf; - data.size =3D strlen(buf); - - if (gnutls_x509_crt_list_import(certs, &certMax, &data, GNUTLS_X509_FM= T_PEM, 0) < 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Unable to import CA certificate list %1$s"), - certFile); - return -1; - } - *ncerts =3D certMax; - - return 0; -} - - -#define MAX_CERTS 16 -static int virNetTLSContextSanityCheckCredentials(bool isServer, - const char *cacertFile, - const char *certFile) -{ - gnutls_x509_crt_t cert =3D NULL; - gnutls_x509_crt_t cacerts[MAX_CERTS] =3D { 0 }; - size_t ncacerts =3D 0; - size_t i; - int ret =3D -1; - - if ((access(certFile, R_OK) =3D=3D 0) && - !(cert =3D virNetTLSContextLoadCertFromFile(certFile, isServer))) - goto cleanup; - if ((access(cacertFile, R_OK) =3D=3D 0) && - virNetTLSContextLoadCACertListFromFile(cacertFile, cacerts, - MAX_CERTS, &ncacerts) < 0) - goto cleanup; - - if (cert && - virNetTLSContextCheckCert(cert, certFile, isServer, false) < 0) - goto cleanup; - - for (i =3D 0; i < ncacerts; i++) { - if (virNetTLSContextCheckCert(cacerts[i], cacertFile, isServer, tr= ue) < 0) - goto cleanup; - } - - if (cert && ncacerts && - virNetTLSContextCheckCertPair(cert, certFile, cacerts, ncacerts, c= acertFile, isServer) < 0) - goto cleanup; - - ret =3D 0; - - cleanup: - if (cert) - gnutls_x509_crt_deinit(cert); - for (i =3D 0; i < ncacerts; i++) - gnutls_x509_crt_deinit(cacerts[i]); - return ret; -} - - static int virNetTLSContextLoadCredentials(virNetTLSContext *ctxt, bool isServer, const char *cacert, @@ -683,7 +224,7 @@ static virNetTLSContext *virNetTLSContextNew(const char= *cacert, } =20 if (sanityCheckCert && - virNetTLSContextSanityCheckCredentials(isServer, cacert, cert) < 0) + virNetTLSCertSanityCheck(isServer, cacert, cert) < 0) goto error; =20 if (virNetTLSContextLoadCredentials(ctxt, isServer, cacert, cacrl, cer= t, key) < 0) @@ -846,7 +387,7 @@ int virNetTLSContextReloadForServer(virNetTLSContext *c= txt, goto error; } =20 - if (virNetTLSContextSanityCheckCredentials(true, cacert, cert)) + if (virNetTLSCertSanityCheck(true, cacert, cert)) goto error; =20 if (virNetTLSContextLoadCredentials(ctxt, true, cacert, cacrl, cert, k= ey)) @@ -876,65 +417,6 @@ virNetTLSContext *virNetTLSContextNewClient(const char= *cacert, sanityCheckCert, requireValidCert, false); } =20 -static int virNetTLSContextCertValidateCA(gnutls_x509_crt_t cert, - bool isServer) -{ - if (virNetTLSContextCheckCertTimes(cert, "[session]", isServer, true) = < 0) - return -1; - - return 0; -} - -static char *virNetTLSContextCertValidate(gnutls_x509_crt_t cert, - bool isServer, - const char *hostname, - const char *const *x509dnACL) -{ - size_t dnamesize =3D 256; - g_autofree char *dname =3D g_new0(char, dnamesize); - int ret; - - if (virNetTLSContextCheckCertTimes(cert, "[session]", - isServer, false) < 0) - return NULL; - - ret =3D gnutls_x509_crt_get_dn(cert, dname, &dnamesize); - if (ret =3D=3D GNUTLS_E_SHORT_MEMORY_BUFFER) { - VIR_DEBUG("Reallocating dname to fit %zu bytes", dnamesize); - dname =3D g_realloc(dname, dnamesize); - ret =3D gnutls_x509_crt_get_dn(cert, dname, &dnamesize); - } - if (ret !=3D 0) { - virReportError(VIR_ERR_SYSTEM_ERROR, - _("Failed to get certificate %1$s distinguished nam= e: %2$s"), - "[session]", gnutls_strerror(ret)); - return NULL; - } - - VIR_DEBUG("Peer DN is %s", dname); - - if (virNetTLSContextCheckCertDN(cert, "[session]", hostname, - dname, x509dnACL) < 0) - return NULL; - - /* !isServer, since on the client, we're validating the - * server's cert, and on the server, the client's cert - */ - if (virNetTLSContextCheckCertBasicConstraints(cert, "[session]", - !isServer, false) < 0) - return NULL; - - if (virNetTLSContextCheckCertKeyUsage(cert, "[session]", - false) < 0) - return NULL; - - /* !isServer - as above */ - if (virNetTLSContextCheckCertKeyPurpose(cert, "[session]", - !isServer) < 0) - return NULL; - - return g_steal_pointer(&dname); -} =20 static int virNetTLSContextValidCertificate(virNetTLSContext *ctxt, virNetTLSSession *sess) @@ -1005,15 +487,16 @@ static int virNetTLSContextValidCertificate(virNetTL= SContext *ctxt, } =20 if (i =3D=3D 0) { - if (!(sess->x509dname =3D virNetTLSContextCertValidate(cert, - sess->isS= erver, - sess->hos= tname, - ctxt->x50= 9dnACL))) { + if (!(sess->x509dname =3D virNetTLSCertValidate(cert, + sess->isServer, + sess->hostname, + ctxt->x509dnACL)= )) { gnutls_x509_crt_deinit(cert); goto authdeny; } } else { - if (virNetTLSContextCertValidateCA(cert, sess->isServer) < 0) { + if (virNetTLSCertValidateCA(cert, + sess->isServer) < 0) { gnutls_x509_crt_deinit(cert); goto authdeny; } --=20 2.43.0 From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717770725267833.0672702125113; Fri, 7 Jun 2024 07:32:05 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 3FF6D2495; Fri, 7 Jun 2024 10:32:03 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 41EAF2460; Fri, 7 Jun 2024 10:26:38 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 120A72341; Fri, 7 Jun 2024 10:26:32 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 06096233B for ; Fri, 7 Jun 2024 10:26:23 -0400 (EDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-682-yXs8Gox0MumjpLsTg3Gx_A-1; Fri, 07 Jun 2024 10:26:21 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0A531800173 for ; Fri, 7 Jun 2024 14:26:21 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id 87F43492BC6; Fri, 7 Jun 2024 14:26:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770383; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=mS7OH2+Fic80SI5plCkvviC/OyOmh8NZeO0IW8jOzPE=; b=EDUkSk2jsPH9TUAxWC00tHG+7Smld12wia7Z7Cux2hya0SfbDr5N7GQ8ZqhQuapdQYQt8O EmGcNFmxEsxEb2oRs2vVVvWx3AbojYwJYdcdwd+mrvJb0FBi1hswLyNZTbt06wktcKg9JX IdO25zwTepXS8bEczBtkEleRGznkG/A= X-MC-Unique: yXs8Gox0MumjpLsTg3Gx_A-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 4/9] docs: fix author credit for virt-pki-validate tool Date: Fri, 7 Jun 2024 15:26:11 +0100 Message-ID: <20240607142616.749339-5-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: UJOJZ42IXQESIQD3QC6KHW4ADWSUKQ5H X-Message-ID-Hash: UJOJZ42IXQESIQD3QC6KHW4ADWSUKQ5H X-MailFrom: berrange@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1717770726787100001 Content-Type: text/plain; charset="utf-8" When first writing the manpage in commit 3decd4f9f1b55000770f4203f98438b6f791256d Author: Daniel P. Berrang=C3=A9 Date: Wed Sep 16 14:42:57 2009 +0100 Make pki_check.sh into an installed & supported tool I incorrectly credited Richard, instead of Daniel, who was the author per commit 62442d578d123de37ab27ae139f1270fc02e837c Author: Daniel Veillard Date: Thu Jul 12 15:47:19 2007 +0000 * docs/libvir.html docs/remote.html: update the remote page, add an index * docs/pki_check.sh: shell script to check the PKI and client/server environment. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- docs/manpages/virt-pki-validate.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manpages/virt-pki-validate.rst b/docs/manpages/virt-pki-v= alidate.rst index 063448f48b..53d5fbe269 100644 --- a/docs/manpages/virt-pki-validate.rst +++ b/docs/manpages/virt-pki-validate.rst @@ -48,7 +48,7 @@ failure a non-zero status will be set. AUTHOR =3D=3D=3D=3D=3D=3D =20 -Richard Jones +Daniel Veillard =20 =20 BUGS --=20 2.43.0 From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717771009933216.52506026361948; Fri, 7 Jun 2024 07:36:49 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id C43CA259F; Fri, 7 Jun 2024 10:36:47 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 108C02473; Fri, 7 Jun 2024 10:26:46 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 37BC623D0; Fri, 7 Jun 2024 10:26:34 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id E6E3A234D for ; Fri, 7 Jun 2024 10:26:25 -0400 (EDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-690-VrhDUAYwPt2Q9ToUjP7p_Q-1; Fri, 07 Jun 2024 10:26:23 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 1E82B800173 for ; Fri, 7 Jun 2024 14:26:22 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5B7FB492BC6; Fri, 7 Jun 2024 14:26:21 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770384; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7lIPj+x3c4T0g1d575rYR/jJalDaDuov703hOfORQGk=; b=EtLiMocYYLTE6Ww6Ia0AQQ1f8wJdVR7aPCDmJ84TBwohqkYZOxlQrHW63wE2k8VZg9J5pG 11JTsNvoga2+YxLavskiUkLNptVgVcsCiDbLNzBPUZhqz1mT5W6cn0nXYIjHsQUt/JmxmI Ch7nVmDtclX2YJ+JYWuFdEgC5C7ztNs= X-MC-Unique: VrhDUAYwPt2Q9ToUjP7p_Q-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 5/9] tools: split off common helpers for host validate tool Date: Fri, 7 Jun 2024 15:26:12 +0100 Message-ID: <20240607142616.749339-6-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: 6XOHDUDBAJT2CENX2PYURAIRPQSB3YWW X-Message-ID-Hash: 6XOHDUDBAJT2CENX2PYURAIRPQSB3YWW X-MailFrom: berrange@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1717771010401100001 Content-Type: text/plain; charset="utf-8" The common messaging helpers will be reused in the new impl of the virt-pki-validate tool. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- po/POTFILES | 1 + tools/meson.build | 1 + tools/virt-host-validate-ch.c | 12 +- tools/virt-host-validate-common.c | 308 +++++++++++------------------- tools/virt-host-validate-common.h | 48 +---- tools/virt-host-validate-lxc.c | 18 +- tools/virt-host-validate-qemu.c | 30 +-- tools/virt-host-validate.c | 2 +- tools/virt-validate-common.c | 110 +++++++++++ tools/virt-validate-common.h | 57 ++++++ 10 files changed, 319 insertions(+), 268 deletions(-) create mode 100644 tools/virt-validate-common.c create mode 100644 tools/virt-validate-common.h diff --git a/po/POTFILES b/po/POTFILES index 0f68c652eb..cb73d07904 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -391,6 +391,7 @@ tools/virt-host-validate-qemu.c tools/virt-host-validate.c tools/virt-login-shell-helper.c tools/virt-pki-query-dn.c +tools/virt-validate-common.c tools/vsh-table.c tools/vsh.c tools/vsh.h diff --git a/tools/meson.build b/tools/meson.build index 1bb84be0be..feb6b7c3ad 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -40,6 +40,7 @@ libvirt_shell_lib =3D static_library( =20 if conf.has('WITH_HOST_VALIDATE') virt_host_validate_sources =3D [ + 'virt-validate-common.c', 'virt-host-validate.c', 'virt-host-validate-common.c', ] diff --git a/tools/virt-host-validate-ch.c b/tools/virt-host-validate-ch.c index 3f96423836..e48c8c825f 100644 --- a/tools/virt-host-validate-ch.c +++ b/tools/virt-host-validate-ch.c @@ -57,21 +57,21 @@ int virHostValidateCh(void) } =20 if (hasVirtFlag) { - virHostMsgCheck("CH", "%s", _("Checking for hardware virtualizatio= n")); + virValidateCheck("CH", "%s", _("Checking for hardware virtualizati= on")); if (hasHwVirt) { - virHostMsgPass(); + virValidatePass(); } else { - virHostMsgFail(VIR_HOST_VALIDATE_FAIL, - _("Only emulated CPUs are available, performanc= e will be significantly limited")); + virValidateFail(VIR_VALIDATE_FAIL, + _("Only emulated CPUs are available, performan= ce will be significantly limited")); ret =3D -1; } } =20 if (hasHwVirt || !hasVirtFlag) { - if (virHostValidateDeviceExists("CH", "/dev/kvm", VIR_HOST_VALIDAT= E_FAIL, + if (virHostValidateDeviceExists("CH", "/dev/kvm", VIR_VALIDATE_FAI= L, kvmhint) < 0) ret =3D -1; - else if (virHostValidateDeviceAccessible("CH", "/dev/kvm", VIR_HOS= T_VALIDATE_FAIL, + else if (virHostValidateDeviceAccessible("CH", "/dev/kvm", VIR_VAL= IDATE_FAIL, _("Check /dev/kvm is worl= d writable or you are in a group that is allowed to access it")) < 0) ret =3D -1; } diff --git a/tools/virt-host-validate-common.c b/tools/virt-host-validate-c= ommon.c index 66f08ac2b3..ad06dfb245 100644 --- a/tools/virt-host-validate-common.c +++ b/tools/virt-host-validate-common.c @@ -45,144 +45,58 @@ VIR_ENUM_IMPL(virHostValidateCPUFlag, "158", "sev"); =20 -static bool quiet; - -void virHostMsgSetQuiet(bool quietFlag) -{ - quiet =3D quietFlag; -} - -void virHostMsgCheck(const char *prefix, - const char *format, - ...) -{ - va_list args; - g_autofree char *msg =3D NULL; - - if (quiet) - return; - - va_start(args, format); - msg =3D g_strdup_vprintf(format, args); - va_end(args); - - fprintf(stdout, "%1$6s: %2$-69s: ", prefix, msg); -} - -static bool virHostMsgWantEscape(void) -{ - static bool detectTty =3D true; - static bool wantEscape; - if (detectTty) { - if (isatty(STDOUT_FILENO)) - wantEscape =3D true; - detectTty =3D false; - } - return wantEscape; -} - -void virHostMsgPass(void) -{ - if (quiet) - return; - - if (virHostMsgWantEscape()) - fprintf(stdout, "\033[32m%s\033[0m\n", _("PASS")); - else - fprintf(stdout, "%s\n", _("PASS")); -} - - -static const char * failMessages[] =3D { - N_("FAIL"), - N_("WARN"), - N_("NOTE"), -}; - -G_STATIC_ASSERT(G_N_ELEMENTS(failMessages) =3D=3D VIR_HOST_VALIDATE_LAST); - -static const char *failEscapeCodes[] =3D { - "\033[31m", - "\033[33m", - "\033[34m", -}; - -G_STATIC_ASSERT(G_N_ELEMENTS(failEscapeCodes) =3D=3D VIR_HOST_VALIDATE_LAS= T); - -void virHostMsgFail(virHostValidateLevel level, - const char *format, - ...) -{ - va_list args; - g_autofree char *msg =3D NULL; - - if (quiet) - return; - - va_start(args, format); - msg =3D g_strdup_vprintf(format, args); - va_end(args); - - if (virHostMsgWantEscape()) - fprintf(stdout, "%s%s\033[0m (%s)\n", - failEscapeCodes[level], _(failMessages[level]), msg); - else - fprintf(stdout, "%s (%s)\n", - _(failMessages[level]), msg); -} - =20 int virHostValidateDeviceExists(const char *hvname, const char *dev_name, - virHostValidateLevel level, + virValidateLevel level, const char *hint) { - virHostMsgCheck(hvname, _("Checking if device '%1$s' exists"), dev_nam= e); + virValidateCheck(hvname, _("Checking if device '%1$s' exists"), dev_na= me); =20 if (access(dev_name, F_OK) < 0) { - virHostMsgFail(level, "%s", hint); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "%s", hint); + return VIR_VALIDATE_FAILURE(level); } =20 - virHostMsgPass(); + virValidatePass(); return 0; } =20 =20 int virHostValidateDeviceAccessible(const char *hvname, const char *dev_name, - virHostValidateLevel level, + virValidateLevel level, const char *hint) { - virHostMsgCheck(hvname, _("Checking if device '%1$s' is accessible"), = dev_name); + virValidateCheck(hvname, _("Checking if device '%1$s' is accessible"),= dev_name); =20 if (access(dev_name, R_OK|W_OK) < 0) { - virHostMsgFail(level, "%s", hint); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "%s", hint); + return VIR_VALIDATE_FAILURE(level); } =20 - virHostMsgPass(); + virValidatePass(); return 0; } =20 =20 int virHostValidateNamespace(const char *hvname, const char *ns_name, - virHostValidateLevel level, + virValidateLevel level, const char *hint) { char nspath[100]; =20 - virHostMsgCheck(hvname, _("Checking for namespace '%1$s'"), ns_name); + virValidateCheck(hvname, _("Checking for namespace '%1$s'"), ns_name); =20 g_snprintf(nspath, sizeof(nspath), "/proc/self/ns/%s", ns_name); =20 if (access(nspath, F_OK) < 0) { - virHostMsgFail(level, "%s", hint); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "%s", hint); + return VIR_VALIDATE_FAILURE(level); } =20 - virHostMsgPass(); + virValidatePass(); return 0; } =20 @@ -248,7 +162,7 @@ virBitmap *virHostValidateGetCPUFlags(void) =20 int virHostValidateLinuxKernel(const char *hvname, int version, - virHostValidateLevel level, + virValidateLevel level, const char *hint) { struct utsname uts; @@ -256,26 +170,26 @@ int virHostValidateLinuxKernel(const char *hvname, =20 uname(&uts); =20 - virHostMsgCheck(hvname, _("Checking for Linux >=3D %1$d.%2$d.%3$d"), - ((version >> 16) & 0xff), - ((version >> 8) & 0xff), - (version & 0xff)); + virValidateCheck(hvname, _("Checking for Linux >=3D %1$d.%2$d.%3$d"), + ((version >> 16) & 0xff), + ((version >> 8) & 0xff), + (version & 0xff)); =20 if (STRNEQ(uts.sysname, "Linux")) { - virHostMsgFail(level, "%s", hint); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "%s", hint); + return VIR_VALIDATE_FAILURE(level); } =20 if (virStringParseVersion(&thisversion, uts.release, true) < 0) { - virHostMsgFail(level, "%s", hint); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "%s", hint); + return VIR_VALIDATE_FAILURE(level); } =20 if (thisversion < version) { - virHostMsgFail(level, "%s", hint); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "%s", hint); + return VIR_VALIDATE_FAILURE(level); } else { - virHostMsgPass(); + virValidatePass(); return 0; } } @@ -283,7 +197,7 @@ int virHostValidateLinuxKernel(const char *hvname, #ifdef __linux__ int virHostValidateCGroupControllers(const char *hvname, int controllers, - virHostValidateLevel level) + virValidateLevel level) { g_autoptr(virCgroup) group =3D NULL; int ret =3D 0; @@ -292,7 +206,7 @@ int virHostValidateCGroupControllers(const char *hvname, if (virCgroupNew("/", -1, &group) < 0) { fprintf(stderr, "Unable to initialize cgroups: %s\n", virGetLastErrorMessage()); - return VIR_HOST_VALIDATE_FAILURE(level); + return VIR_VALIDATE_FAILURE(level); } =20 for (i =3D 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { @@ -302,15 +216,15 @@ int virHostValidateCGroupControllers(const char *hvna= me, if (!(controllers & flag)) continue; =20 - virHostMsgCheck(hvname, _("Checking for cgroup '%1$s' controller s= upport"), cg_name); + virValidateCheck(hvname, _("Checking for cgroup '%1$s' controller = support"), cg_name); =20 if (!virCgroupHasController(group, i)) { - ret =3D VIR_HOST_VALIDATE_FAILURE(level); - virHostMsgFail(level, "Enable '%s' in kernel Kconfig file or " - "mount/enable cgroup controller in your system", - cg_name); + ret =3D VIR_VALIDATE_FAILURE(level); + virValidateFail(level, "Enable '%s' in kernel Kconfig file or " + "mount/enable cgroup controller in your system= ", + cg_name); } else { - virHostMsgPass(); + virValidatePass(); } } =20 @@ -319,15 +233,15 @@ int virHostValidateCGroupControllers(const char *hvna= me, #else /* !__linux__ */ int virHostValidateCGroupControllers(const char *hvname G_GNUC_UNUSED, int controllers G_GNUC_UNUSED, - virHostValidateLevel level) + virValidateLevel level) { - virHostMsgFail(level, "%s", "This platform does not support cgroups"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "%s", "This platform does not support cgroups"); + return VIR_VALIDATE_FAILURE(level); } #endif /* !__linux__ */ =20 int virHostValidateIOMMU(const char *hvname, - virHostValidateLevel level) + virValidateLevel level) { g_autoptr(virBitmap) flags =3D NULL; struct stat sb; @@ -337,7 +251,7 @@ int virHostValidateIOMMU(const char *hvname, struct dirent *dent; int rc; =20 - virHostMsgCheck(hvname, "%s", _("Checking for device assignment IOMMU = support")); + virValidateCheck(hvname, "%s", _("Checking for device assignment IOMMU= support")); =20 flags =3D virHostValidateGetCPUFlags(); =20 @@ -348,28 +262,28 @@ int virHostValidateIOMMU(const char *hvname, =20 if (isIntel) { if (access("/sys/firmware/acpi/tables/DMAR", F_OK) =3D=3D 0) { - virHostMsgPass(); + virValidatePass(); bootarg =3D "intel_iommu=3Don"; } else { - virHostMsgFail(level, - "No ACPI DMAR table found, IOMMU either " - "disabled in BIOS or not supported by this " - "hardware platform"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "No ACPI DMAR table found, IOMMU either " + "disabled in BIOS or not supported by this " + "hardware platform"); + return VIR_VALIDATE_FAILURE(level); } } else if (isAMD) { if (access("/sys/firmware/acpi/tables/IVRS", F_OK) =3D=3D 0) { - virHostMsgPass(); + virValidatePass(); bootarg =3D "iommu=3Dpt iommu=3D1"; } else { - virHostMsgFail(level, - "No ACPI IVRS table found, IOMMU either " - "disabled in BIOS or not supported by this " - "hardware platform"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "No ACPI IVRS table found, IOMMU either " + "disabled in BIOS or not supported by this " + "hardware platform"); + return VIR_VALIDATE_FAILURE(level); } } else if (ARCH_IS_PPC64(arch)) { - virHostMsgPass(); + virValidatePass(); } else if (ARCH_IS_S390(arch)) { g_autoptr(DIR) dir =3D NULL; =20 @@ -378,41 +292,41 @@ int virHostValidateIOMMU(const char *hvname, * no PCI devices the directory is still there but is * empty. */ if (!virDirOpen(&dir, "/sys/bus/pci/devices")) { - virHostMsgFail(VIR_HOST_VALIDATE_NOTE, - "Skipped - PCI support disabled"); - return VIR_HOST_VALIDATE_FAILURE(VIR_HOST_VALIDATE_NOTE); + virValidateFail(VIR_VALIDATE_NOTE, + "Skipped - PCI support disabled"); + return VIR_VALIDATE_FAILURE(VIR_VALIDATE_NOTE); } rc =3D virDirRead(dir, &dent, NULL); if (rc <=3D 0) { - virHostMsgFail(VIR_HOST_VALIDATE_NOTE, - "Skipped - No PCI devices are online"); - return VIR_HOST_VALIDATE_FAILURE(VIR_HOST_VALIDATE_NOTE); + virValidateFail(VIR_VALIDATE_NOTE, + "Skipped - No PCI devices are online"); + return VIR_VALIDATE_FAILURE(VIR_VALIDATE_NOTE); } - virHostMsgPass(); + virValidatePass(); } else if (ARCH_IS_ARM(arch)) { if (access("/sys/firmware/acpi/tables/IORT", F_OK) !=3D 0) { - virHostMsgFail(level, - "No ACPI IORT table found, IOMMU not " - "supported by this hardware platform"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "No ACPI IORT table found, IOMMU not " + "supported by this hardware platform"); + return VIR_VALIDATE_FAILURE(level); } else { rc =3D virAcpiHasSMMU(); if (rc < 0) { - virHostMsgFail(level, - "Failed to parse ACPI IORT table"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "Failed to parse ACPI IORT table"); + return VIR_VALIDATE_FAILURE(level); } else if (rc =3D=3D 0) { - virHostMsgFail(level, - "No SMMU found"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "No SMMU found"); + return VIR_VALIDATE_FAILURE(level); } else { - virHostMsgPass(); + virValidatePass(); } } } else { - virHostMsgFail(level, - "Unknown if this platform has IOMMU support"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "Unknown if this platform has IOMMU support"); + return VIR_VALIDATE_FAILURE(level); } =20 =20 @@ -423,17 +337,17 @@ int virHostValidateIOMMU(const char *hvname, if (!S_ISDIR(sb.st_mode)) return 0; =20 - virHostMsgCheck(hvname, "%s", _("Checking if IOMMU is enabled by kerne= l")); + virValidateCheck(hvname, "%s", _("Checking if IOMMU is enabled by kern= el")); if (sb.st_nlink <=3D 2) { if (bootarg) - virHostMsgFail(level, - "IOMMU appears to be disabled in kernel. " - "Add %s to kernel cmdline arguments", bootarg); + virValidateFail(level, + "IOMMU appears to be disabled in kernel. " + "Add %s to kernel cmdline arguments", bootarg); else - virHostMsgFail(level, "IOMMU capability not compiled into kern= el."); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "IOMMU capability not compiled into ker= nel."); + return VIR_VALIDATE_FAILURE(level); } - virHostMsgPass(); + virValidatePass(); return 0; } =20 @@ -466,7 +380,7 @@ bool virHostKernelModuleIsLoaded(const char *module) =20 =20 int virHostValidateSecureGuests(const char *hvname, - virHostValidateLevel level) + virValidateLevel level) { g_autoptr(virBitmap) flags =3D NULL; bool hasFac158 =3D false; @@ -483,13 +397,13 @@ int virHostValidateSecureGuests(const char *hvname, else if (flags && virBitmapIsBitSet(flags, VIR_HOST_VALIDATE_CPU_FLAG_= SEV)) hasAMDSev =3D true; =20 - virHostMsgCheck(hvname, "%s", _("Checking for secure guest support")); + virValidateCheck(hvname, "%s", _("Checking for secure guest support")); if (ARCH_IS_S390(arch)) { if (hasFac158) { if (!virFileIsDir("/sys/firmware/uv")) { - virHostMsgFail(level, "IBM Secure Execution not supported = by " - "the currently used kernel"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "IBM Secure Execution not supported= by " + "the currently used kernel"); + return VIR_VALIDATE_FAILURE(level); } =20 /* we're prefix matching rather than equality matching here, b= ecause @@ -501,47 +415,47 @@ int virHostValidateSecureGuests(const char *hvname, G_N_ELEMENTS(kIBMValues), VIR_KERNEL_CMDLINE_FLAGS_SEARCH= _FIRST | VIR_KERNEL_CMDLINE_FLAGS_CMP_PR= EFIX)) { - virHostMsgPass(); + virValidatePass(); return 1; } else { - virHostMsgFail(level, - "IBM Secure Execution appears to be disable= d " - "in kernel. Add prot_virt=3D1 to kernel cmd= line " - "arguments"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "IBM Secure Execution appears to be disabl= ed " + "in kernel. Add prot_virt=3D1 to kernel cm= dline " + "arguments"); + return VIR_VALIDATE_FAILURE(level); } } else { - virHostMsgFail(level, "Hardware or firmware does not provide " - "support for IBM Secure Execution"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "Hardware or firmware does not provide " + "support for IBM Secure Execution"); + return VIR_VALIDATE_FAILURE(level); } } else if (hasAMDSev) { if (virFileReadValueString(&mod_value, "/sys/module/kvm_amd/parame= ters/sev") < 0) { - virHostMsgFail(level, "AMD Secure Encrypted Virtualization not= " - "supported by the currently used kernel"= ); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, "AMD Secure Encrypted Virtualization no= t " + "supported by the currently used kernel"); + return VIR_VALIDATE_FAILURE(level); } =20 if (mod_value[0] !=3D '1' && mod_value[0] !=3D 'Y' && mod_value[0]= !=3D 'y') { - virHostMsgFail(level, - "AMD Secure Encrypted Virtualization appears to= be " - "disabled in kernel. Add kvm_amd.sev=3D1 " - "to the kernel cmdline arguments"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "AMD Secure Encrypted Virtualization appears t= o be " + "disabled in kernel. Add kvm_amd.sev=3D1 " + "to the kernel cmdline arguments"); + return VIR_VALIDATE_FAILURE(level); } =20 if (virFileExists("/dev/sev")) { - virHostMsgPass(); + virValidatePass(); return 1; } else { - virHostMsgFail(level, - "AMD Secure Encrypted Virtualization appears to= be " - "disabled in firmware."); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "AMD Secure Encrypted Virtualization appears t= o be " + "disabled in firmware."); + return VIR_VALIDATE_FAILURE(level); } } =20 - virHostMsgFail(level, - "Unknown if this platform has Secure Guest support"); - return VIR_HOST_VALIDATE_FAILURE(level); + virValidateFail(level, + "Unknown if this platform has Secure Guest support"); + return VIR_VALIDATE_FAILURE(level); } diff --git a/tools/virt-host-validate-common.h b/tools/virt-host-validate-c= ommon.h index 9334fa8588..7fb3545fe3 100644 --- a/tools/virt-host-validate-common.h +++ b/tools/virt-host-validate-common.h @@ -24,14 +24,7 @@ #include "internal.h" #include "virbitmap.h" #include "virenum.h" - -typedef enum { - VIR_HOST_VALIDATE_FAIL, - VIR_HOST_VALIDATE_WARN, - VIR_HOST_VALIDATE_NOTE, - - VIR_HOST_VALIDATE_LAST, -} virHostValidateLevel; +#include "virt-validate-common.h" =20 typedef enum { VIR_HOST_VALIDATE_CPU_FLAG_VMX =3D 0, @@ -45,61 +38,36 @@ typedef enum { =20 VIR_ENUM_DECL(virHostValidateCPUFlag); =20 -/** - * VIR_HOST_VALIDATE_FAILURE - * @level: the virHostValidateLevel to be checked - * - * This macro is to be used in to return a failures based on the - * virHostValidateLevel use in the function. - * - * If the virHostValidateLevel is VIR_HOST_VALIDATE_FAIL, -1 is returned. - * 0 is returned otherwise (as the virHosValidateLevel is then either a - * Warn or a Note). - */ - -#define VIR_HOST_VALIDATE_FAILURE(level) (level =3D=3D VIR_HOST_VALIDATE_F= AIL) ? -1 : 0 - -void virHostMsgSetQuiet(bool quietFlag); - -void virHostMsgCheck(const char *prefix, - const char *format, - ...) G_GNUC_PRINTF(2, 3); - -void virHostMsgPass(void); -void virHostMsgFail(virHostValidateLevel level, - const char *format, - ...) G_GNUC_PRINTF(2, 3); - int virHostValidateDeviceExists(const char *hvname, const char *dev_name, - virHostValidateLevel level, + virValidateLevel level, const char *hint); =20 int virHostValidateDeviceAccessible(const char *hvname, const char *dev_name, - virHostValidateLevel level, + virValidateLevel level, const char *hint); =20 virBitmap *virHostValidateGetCPUFlags(void); =20 int virHostValidateLinuxKernel(const char *hvname, int version, - virHostValidateLevel level, + virValidateLevel level, const char *hint); =20 int virHostValidateNamespace(const char *hvname, const char *ns_name, - virHostValidateLevel level, + virValidateLevel level, const char *hint); =20 int virHostValidateCGroupControllers(const char *hvname, int controllers, - virHostValidateLevel level); + virValidateLevel level); =20 int virHostValidateIOMMU(const char *hvname, - virHostValidateLevel level); + virValidateLevel level); =20 int virHostValidateSecureGuests(const char *hvname, - virHostValidateLevel level); + virValidateLevel level); =20 bool virHostKernelModuleIsLoaded(const char *module); diff --git a/tools/virt-host-validate-lxc.c b/tools/virt-host-validate-lxc.c index 8613f37cc7..5d6dbdf647 100644 --- a/tools/virt-host-validate-lxc.c +++ b/tools/virt-host-validate-lxc.c @@ -30,37 +30,37 @@ int virHostValidateLXC(void) int ret =3D 0; =20 if (virHostValidateLinuxKernel("LXC", (2 << 16) | (6 << 8) | 26, - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, _("Upgrade to a kernel supporting names= paces")) < 0) ret =3D -1; =20 if (virHostValidateNamespace("LXC", "ipc", - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, _("IPC namespace support is required")) <= 0) ret =3D -1; =20 if (virHostValidateNamespace("LXC", "mnt", - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, _("Mount namespace support is required"))= < 0) ret =3D -1; =20 if (virHostValidateNamespace("LXC", "pid", - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, _("PID namespace support is required")) <= 0) ret =3D -1; =20 if (virHostValidateNamespace("LXC", "uts", - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, _("UTS namespace support is required")) <= 0) ret =3D -1; =20 if (virHostValidateNamespace("LXC", "net", - VIR_HOST_VALIDATE_WARN, + VIR_VALIDATE_WARN, _("Network namespace support is recommend= ed")) < 0) ret =3D -1; =20 if (virHostValidateNamespace("LXC", "user", - VIR_HOST_VALIDATE_WARN, + VIR_VALIDATE_WARN, _("User namespace support is recommended"= )) < 0) ret =3D -1; =20 @@ -72,13 +72,13 @@ int virHostValidateLXC(void) (1 << VIR_CGROUP_CONTROLLER_DEVIC= ES) | (1 << VIR_CGROUP_CONTROLLER_FREEZ= ER) | (1 << VIR_CGROUP_CONTROLLER_BLKIO= ), - VIR_HOST_VALIDATE_FAIL) < 0) { + VIR_VALIDATE_FAIL) < 0) { ret =3D -1; } =20 #if WITH_FUSE if (virHostValidateDeviceExists("LXC", "/sys/fs/fuse/connections", - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, _("Load the 'fuse' module to enable /p= roc/ overrides")) < 0) ret =3D -1; #endif diff --git a/tools/virt-host-validate-qemu.c b/tools/virt-host-validate-qem= u.c index b685fa01ba..833bb1b914 100644 --- a/tools/virt-host-validate-qemu.c +++ b/tools/virt-host-validate-qemu.c @@ -64,44 +64,44 @@ int virHostValidateQEMU(void) } =20 if (hasVirtFlag) { - virHostMsgCheck("QEMU", "%s", _("Checking for hardware virtualizat= ion")); + virValidateCheck("QEMU", "%s", _("Checking for hardware virtualiza= tion")); if (hasHwVirt) { - virHostMsgPass(); + virValidatePass(); } else { - virHostMsgFail(VIR_HOST_VALIDATE_FAIL, - _("Host not compatible with KVM; HW virtualizat= ion CPU features not found. Only emulated CPUs are available; performance w= ill be significantly limited")); + virValidateFail(VIR_VALIDATE_FAIL, + _("Host not compatible with KVM; HW virtualiza= tion CPU features not found. Only emulated CPUs are available; performance = will be significantly limited")); ret =3D -1; } } =20 if (hasHwVirt || !hasVirtFlag) { if (virHostValidateDeviceExists("QEMU", "/dev/kvm", - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, kvmhint) <0) ret =3D -1; else if (virHostValidateDeviceAccessible("QEMU", "/dev/kvm", - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, _("Check /dev/kvm is worl= d writable or you are in a group that is allowed to access it")) < 0) ret =3D -1; } =20 if (arch =3D=3D VIR_ARCH_PPC64 || arch =3D=3D VIR_ARCH_PPC64LE) { - virHostMsgCheck("QEMU", "%s", _("Checking for PowerPC KVM module l= oaded")); + virValidateCheck("QEMU", "%s", _("Checking for PowerPC KVM module = loaded")); =20 if (!virHostKernelModuleIsLoaded("kvm_hv")) - virHostMsgFail(VIR_HOST_VALIDATE_WARN, - _("Load kvm_hv for better performance")); + virValidateFail(VIR_VALIDATE_WARN, + _("Load kvm_hv for better performance")); else - virHostMsgPass(); + virValidatePass(); } =20 if (virHostValidateDeviceExists("QEMU", "/dev/vhost-net", - VIR_HOST_VALIDATE_WARN, + VIR_VALIDATE_WARN, _("Load the 'vhost_net' module to impr= ove performance of virtio networking")) < 0) ret =3D -1; =20 if (virHostValidateDeviceExists("QEMU", "/dev/net/tun", - VIR_HOST_VALIDATE_FAIL, + VIR_VALIDATE_FAIL, _("Load the 'tun' module to enable net= working for QEMU guests")) < 0) ret =3D -1; =20 @@ -112,16 +112,16 @@ int virHostValidateQEMU(void) (1 << VIR_CGROUP_CONTROLLER_CPUSE= T) | (1 << VIR_CGROUP_CONTROLLER_DEVIC= ES) | (1 << VIR_CGROUP_CONTROLLER_BLKIO= ), - VIR_HOST_VALIDATE_WARN) < 0) { + VIR_VALIDATE_WARN) < 0) { ret =3D -1; } =20 if (virHostValidateIOMMU("QEMU", - VIR_HOST_VALIDATE_WARN) < 0) + VIR_VALIDATE_WARN) < 0) ret =3D -1; =20 if (virHostValidateSecureGuests("QEMU", - VIR_HOST_VALIDATE_WARN) < 0) + VIR_VALIDATE_WARN) < 0) ret =3D -1; =20 return ret; diff --git a/tools/virt-host-validate.c b/tools/virt-host-validate.c index d9fa52c310..426648a5d3 100644 --- a/tools/virt-host-validate.c +++ b/tools/virt-host-validate.c @@ -124,7 +124,7 @@ main(int argc, char **argv) if (argc > 1) hvname =3D argv[optind]; =20 - virHostMsgSetQuiet(quiet); + virValidateSetQuiet(quiet); =20 #if WITH_QEMU if (!hvname || STREQ(hvname, "qemu")) { diff --git a/tools/virt-validate-common.c b/tools/virt-validate-common.c new file mode 100644 index 0000000000..88c10e846f --- /dev/null +++ b/tools/virt-validate-common.c @@ -0,0 +1,110 @@ +/* + * virt-validate-common.c: Sanity check helper APIs + * + * Copyright (C) 2012-2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + */ + +#include + +#include "virt-validate-common.h" + +static bool quiet; + +void virValidateSetQuiet(bool quietFlag) +{ + quiet =3D quietFlag; +} + +void virValidateCheck(const char *prefix, + const char *format, + ...) +{ + va_list args; + g_autofree char *msg =3D NULL; + + if (quiet) + return; + + va_start(args, format); + msg =3D g_strdup_vprintf(format, args); + va_end(args); + + fprintf(stdout, "%1$6s: %2$-69s: ", prefix, msg); +} + +static bool virValidateWantEscape(void) +{ + static bool detectTty =3D true; + static bool wantEscape; + if (detectTty) { + if (isatty(STDOUT_FILENO)) + wantEscape =3D true; + detectTty =3D false; + } + return wantEscape; +} + +void virValidatePass(void) +{ + if (quiet) + return; + + if (virValidateWantEscape()) + fprintf(stdout, "\033[32m%s\033[0m\n", _("PASS")); + else + fprintf(stdout, "%s\n", _("PASS")); +} + + +static const char * failMessages[] =3D { + N_("FAIL"), + N_("WARN"), + N_("NOTE"), +}; + +G_STATIC_ASSERT(G_N_ELEMENTS(failMessages) =3D=3D VIR_VALIDATE_LAST); + +static const char *failEscapeCodes[] =3D { + "\033[31m", + "\033[33m", + "\033[34m", +}; + +G_STATIC_ASSERT(G_N_ELEMENTS(failEscapeCodes) =3D=3D VIR_VALIDATE_LAST); + +void virValidateFail(virValidateLevel level, + const char *format, + ...) +{ + va_list args; + g_autofree char *msg =3D NULL; + + if (quiet) + return; + + va_start(args, format); + msg =3D g_strdup_vprintf(format, args); + va_end(args); + + if (virValidateWantEscape()) + fprintf(stdout, "%s%s\033[0m (%s)\n", + failEscapeCodes[level], _(failMessages[level]), msg); + else + fprintf(stdout, "%s (%s)\n", + _(failMessages[level]), msg); +} diff --git a/tools/virt-validate-common.h b/tools/virt-validate-common.h new file mode 100644 index 0000000000..7f7c373a66 --- /dev/null +++ b/tools/virt-validate-common.h @@ -0,0 +1,57 @@ +/* + * virt-validate-common.h: Sanity check helper APIs + * + * Copyright (C) 2012-2024 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + */ + +#pragma once + +#include "internal.h" + +typedef enum { + VIR_VALIDATE_FAIL, + VIR_VALIDATE_WARN, + VIR_VALIDATE_NOTE, + + VIR_VALIDATE_LAST, +} virValidateLevel; + +/** + * VIR_VALIDATE_FAILURE + * @level: the virValidateLevel to be checked + * + * This macro is to be used in to return a failures based on the + * virValidateLevel use in the function. + * + * If the virValidateLevel is VIR_VALIDATE_FAIL, -1 is returned. + * 0 is returned otherwise (as the virValidateLevel is then either a + * Warn or a Note). + */ + +#define VIR_VALIDATE_FAILURE(level) (level =3D=3D VIR_VALIDATE_FAIL) ? -1 = : 0 + +void virValidateSetQuiet(bool quietFlag); + +void virValidateCheck(const char *prefix, + const char *format, + ...) G_GNUC_PRINTF(2, 3); + +void virValidatePass(void); +void virValidateFail(virValidateLevel level, + const char *format, + ...) G_GNUC_PRINTF(2, 3); --=20 2.43.0 From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717772078013518.5513006766452; Fri, 7 Jun 2024 07:54:38 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 4D5132691; Fri, 7 Jun 2024 10:54:36 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id A705A26A3; Fri, 7 Jun 2024 10:47:24 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 5CA7025B5; Fri, 7 Jun 2024 10:47:17 -0400 (EDT) Received: from mx1.osci.io (polly.osci.io [8.43.85.229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 0BDD325D3 for ; Fri, 7 Jun 2024 10:44:54 -0400 (EDT) Received: by mx1.osci.io (Postfix, from userid 994) id ECCFE2254F; Fri, 7 Jun 2024 10:44:53 -0400 (EDT) Received: from mx3.osci.io (carla.osci.io [IPv6:2607:f0d0:1e02:35::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits)) (No client certificate requested) by mx1.osci.io (Postfix) with ESMTPS id 0E8762254B for ; Fri, 7 Jun 2024 10:44:46 -0400 (EDT) Received: by mx3.osci.io (Postfix, from userid 990) id 3BB2C30721DA; Fri, 7 Jun 2024 09:33:01 -0500 (CDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by mx3.osci.io (Postfix) with ESMTPS id 129BD30721D2 for ; Fri, 7 Jun 2024 09:33:00 -0500 (CDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-45-72aeA7BWPYWJ0BhiD243Hg-1; Fri, 07 Jun 2024 10:26:23 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C9DFD85A5B5 for ; Fri, 7 Jun 2024 14:26:22 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id 55923492BC6; Fri, 7 Jun 2024 14:26:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770385; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eo9d3bmZG8FVsPK25LHj1OvTAE7pwTBnxGWI89bOAaU=; b=L7RjAGWr71ISR/X6rMzOlKdKCS+PMSvCpBRQCouAetu96zqhGLjieY5LXYeLvqTNVdHnjs ZY6IwjvlefADWeyUHKvm2y0qube9N6iJcwSWluy3gizKPUD4LaUAnlUr97gp7+mxRR4Nu4 1duGcaPdkVvLh5pdxFqoEvtuXzQVKmI= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770517; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eo9d3bmZG8FVsPK25LHj1OvTAE7pwTBnxGWI89bOAaU=; b=jAzXN7iIYFqS7E9Rs78r1buKNgnThAe5O40lG5PDmSNPsHH6i4GXobye1DfBTaUbejAzbO V8YGzg/LoVW7ZdP13YtgJ0Gnv8ZK/Gk/0+LcsN9XIdZ2zigRS9zIFsb0hLcIFRyVpZYQ0U HDCkV+7Os7Rk068vKDx4Z2HTRxUSsgg= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770648; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eo9d3bmZG8FVsPK25LHj1OvTAE7pwTBnxGWI89bOAaU=; b=cRIsSIq9zsdXaK55qQhCNEqvsBZLOGt4ngYtpsKj4WA304cAuC9BrPo3+JudpGzcfYEx+K IMw/cYgom2okb39nlzYw2VmN7M3S76qaB/2ZF0/rcEPCNqCd7VV5P0Ylb9mP+674bw+tLJ YEgdyE/KRRqO5Ye5CRGTvMW0RYJqYxI= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770779; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=eo9d3bmZG8FVsPK25LHj1OvTAE7pwTBnxGWI89bOAaU=; b=RMcDowUur3La9Yr5XXCay4YLtu/0K3zo9CUrAyTaLhncvD36Wa2GatNwbVZY/5wcatdSVm eJH2dH784gxpeuMFWVySLiQuEzWlIA3u0drsEDmn6mq0McIuHcu8BcDMq9VvKafgPgnqnR LbqAhz/uau669QjXdEYCVie1tlaLtDA= X-MC-Unique: 72aeA7BWPYWJ0BhiD243Hg-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 6/9] tools: drop unused --version argument Date: Fri, 7 Jun 2024 15:26:13 +0100 Message-ID: <20240607142616.749339-7-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: ZN7ETWC3ANJRTU7XL5TFAVL4CQ6UN5UN X-Message-ID-Hash: ZN7ETWC3ANJRTU7XL5TFAVL4CQ6UN5UN X-MailFrom: SRS0=RZ0v=NJ=redhat.com=berrange@osci.io X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (found 4 invalid signatures) X-ZM-MESSAGEID: 1717772078444100001 Content-Type: text/plain; charset="utf-8" These tools never supported passing an argument to --version, this is a copy+paste mistake from virsh, which did support an argument. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- tools/virt-login-shell-helper.c | 2 +- tools/virt-pki-query-dn.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/virt-login-shell-helper.c b/tools/virt-login-shell-helpe= r.c index 1627ba85e5..cb59b5dec0 100644 --- a/tools/virt-login-shell-helper.c +++ b/tools/virt-login-shell-helper.c @@ -180,7 +180,7 @@ main(int argc, char **argv) =20 struct option opt[] =3D { { "help", no_argument, NULL, 'h' }, - { "version", optional_argument, NULL, 'V' }, + { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 }, }; if (virInitialize() < 0) { diff --git a/tools/virt-pki-query-dn.c b/tools/virt-pki-query-dn.c index c8196e32e3..5bf6717c4f 100644 --- a/tools/virt-pki-query-dn.c +++ b/tools/virt-pki-query-dn.c @@ -62,7 +62,7 @@ main(int argc, =20 struct option opt[] =3D { { "help", no_argument, NULL, 'h' }, - { "version", optional_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 }, }; =20 --=20 2.43.0 From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717771169811730.2798481861461; Fri, 7 Jun 2024 07:39:29 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 4CE46256A; Fri, 7 Jun 2024 10:39:27 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 6BC43248A; Fri, 7 Jun 2024 10:26:50 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 5C98A23D0; Fri, 7 Jun 2024 10:26:34 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 6103A236E for ; Fri, 7 Jun 2024 10:26:26 -0400 (EDT) Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-632-T3lct0TMN0OZtazWP9Sk2g-1; Fri, 07 Jun 2024 10:26:23 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 857233C025AC for ; Fri, 7 Jun 2024 14:26:23 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0B691492BC6; Fri, 7 Jun 2024 14:26:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770385; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hOx4dIJ7KCzeyQ7r2JnqJNq2LPZLTqTSTqPGZgHYiX4=; b=hyBly9JQpWPc9AbVcvA/uAyLEg6deQ2HNFoNApkN2OqotSZOn+eKxZn1txwui+vn2U842g fqR9FdYhFevG6ng6cqhd/mvNrqQOwNvjh5eIBMJAuAHGR87TLPE0N1CKX0wk1LfKLwX2UE PX4QwsowUyfzJ13eLddZIZcWol4nDz4= X-MC-Unique: T3lct0TMN0OZtazWP9Sk2g-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 7/9] tools: stop checking init scripts & iptables config Date: Fri, 7 Jun 2024 15:26:14 +0100 Message-ID: <20240607142616.749339-8-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: H6B7PMU63TZSBEDA3JLZMTVZDM3YXLAH X-Message-ID-Hash: H6B7PMU63TZSBEDA3JLZMTVZDM3YXLAH X-MailFrom: berrange@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1717771170993100001 Content-Type: text/plain; charset="utf-8" The /etc/sysconfig/libvirtd file is a Fedora/RHEL specific concept. Since those distros switched to systemd socket activation, the existance of --listen parameter in /etc/sysconfig/libvirtd is no longer a reliable check. This was further degraded with the switch to modular daemons where virtproxyd takes over the role. The /etc/sysconfig/iptables file is a Fedora/RHEL specific concept. Since those distros switched to firewalld, this file is no longer a reliable check. Rather than complicating these checks, just remove them, so that the virt-pki-validate tool focuses exclusively on TLS configuration validation. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- tools/virt-pki-validate.in | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/tools/virt-pki-validate.in b/tools/virt-pki-validate.in index c91f247ba5..c77daa9862 100644 --- a/tools/virt-pki-validate.in +++ b/tools/virt-pki-validate.in @@ -73,7 +73,6 @@ echo Found "$CERTOOL" # SYSCONFDIR=3D"@sysconfdir@" PKI=3D"$SYSCONFDIR/pki" -INITCONFDIR=3D"@initconfdir@" if [ ! -d "$PKI" ] then echo the $PKI directory is missing, it is usually @@ -293,31 +292,4 @@ else SERVER=3D0 fi =20 -if [ "$SERVER" =3D "1" ] -then - if [ -r "$INITCONFDIR"/libvirtd ] - then - if grep "^LIBVIRTD_ARGS.*--listen" "$INITCONFDIR"/libvirtd \ - >/dev/null 2>&1 - then - : - else - echo Make sure "$INITCONFDIR"/libvirtd is setup to listen to - echo TCP/IP connections and restart the libvirtd service - fi - fi - if [ -r "$INITCONFDIR"/iptables ] - then - if grep "$PORT" "$INITCONFDIR"/iptables >/dev/null 2>&1 - then - : - else - echo Make sure "$INITCONFDIR"/iptables is setup to allow - echo incoming TCP/IP connections on port $PORT and - echo restart the iptables service - fi - fi -fi - - exit 0 --=20 2.43.0 From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717770855563767.3912273404773; Fri, 7 Jun 2024 07:34:15 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id F3D3F2577; Fri, 7 Jun 2024 10:34:13 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id F25F82471; Fri, 7 Jun 2024 10:26:42 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 7009523C0; Fri, 7 Jun 2024 10:26:33 -0400 (EDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id D10212372 for ; Fri, 7 Jun 2024 10:26:27 -0400 (EDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-122-Bvj3hau7MJurXfFx9sFXTA-1; Fri, 07 Jun 2024 10:26:24 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8DC6785A5B5 for ; Fri, 7 Jun 2024 14:26:24 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id E43EA492BC6; Fri, 7 Jun 2024 14:26:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: * X-Spam-Status: No, score=1.9 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,LOTS_OF_MONEY,MAILING_LIST_MULTI, MONEY_NOHTML,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H4,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770386; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=b5xzPIC+AW6BNH8u9iSBQO5BcDrA8i4lrrNp8bsl2TM=; b=BKlLmH/mveOzX55VjrzTeQircE044oL2kgZjSL1dd3JV7Jtij/7HY3dpC13l+ZjFwJoFTV l5jFc47BaTQ1TnpjUNai7OfXWMn1zAPj+X+6x1C8O0SERPKKmxcA/GxPBEdx0l8jDERPA1 UuW8ew/fVrzyVEyG0pB7yaSB54fcE6Y= X-MC-Unique: Bvj3hau7MJurXfFx9sFXTA-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 8/9] tools: reimplement virt-pki-validate in C Date: Fri, 7 Jun 2024 15:26:15 +0100 Message-ID: <20240607142616.749339-9-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: YLIATJK75IXY57QIJXPR5SWT4BICOSM4 X-Message-ID-Hash: YLIATJK75IXY57QIJXPR5SWT4BICOSM4 X-MailFrom: berrange@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1717770857477100001 Content-Type: text/plain; charset="utf-8" The virt-pki-validate tool is currently a shell script. We have a general goal of eliminating use of shell in the project. By doing a new implementation in C, we can also make use of our more thorough sanity checking code to validate the certificate setup. This new implementation the same output format as the host validation tool for a more consistent user experiance. It also eliminates the requirement to have certtool installed on libvirt hosts, which has been an issue for Fedora flatpak packages since certtool isn't in the default platform runtime. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- docs/manpages/virt-pki-validate.rst | 4 +- libvirt.spec.in | 2 - po/POTFILES | 1 + tools/meson.build | 30 ++- tools/virt-pki-validate.c | 309 ++++++++++++++++++++++++++++ tools/virt-pki-validate.in | 295 -------------------------- 6 files changed, 337 insertions(+), 304 deletions(-) create mode 100644 tools/virt-pki-validate.c delete mode 100644 tools/virt-pki-validate.in diff --git a/docs/manpages/virt-pki-validate.rst b/docs/manpages/virt-pki-v= alidate.rst index 53d5fbe269..cf17bad790 100644 --- a/docs/manpages/virt-pki-validate.rst +++ b/docs/manpages/virt-pki-validate.rst @@ -48,7 +48,7 @@ failure a non-zero status will be set. AUTHOR =3D=3D=3D=3D=3D=3D =20 -Daniel Veillard +Daniel Veillard, Daniel P. Berrang=C3=A9 =20 =20 BUGS @@ -70,7 +70,7 @@ Alternatively, you may report bugs to your software distr= ibutor / vendor. COPYRIGHT =3D=3D=3D=3D=3D=3D=3D=3D=3D =20 -Copyright (C) 2006-2012 by Red Hat, Inc. +Copyright (C) 2006-2024 by Red Hat, Inc. =20 =20 LICENSE diff --git a/libvirt.spec.in b/libvirt.spec.in index 244e5e824c..2570c2458a 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -1032,8 +1032,6 @@ capabilities of VirtualBox %package client Summary: Client side utilities of the libvirt library Requires: libvirt-libs =3D %{version}-%{release} -# Needed by virt-pki-validate script. -Requires: gnutls-utils =20 # Ensure smooth upgrades Obsoletes: libvirt-bash-completion < 7.3.0 diff --git a/po/POTFILES b/po/POTFILES index cb73d07904..4bfbb91164 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -391,6 +391,7 @@ tools/virt-host-validate-qemu.c tools/virt-host-validate.c tools/virt-login-shell-helper.c tools/virt-pki-query-dn.c +tools/virt-pki-validate.c tools/virt-validate-common.c tools/vsh-table.c tools/vsh.c diff --git a/tools/meson.build b/tools/meson.build index feb6b7c3ad..a58f5d4175 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -255,13 +255,33 @@ configure_file( install_mode: 'rwxr-xr-x', ) =20 -configure_file( - input: 'virt-pki-validate.in', - output: '@BASENAME@', - configuration: tools_conf, +executable( + 'virt-pki-validate', + tlsconfig_sources + [ + 'virt-validate-common.c', + 'virt-pki-validate.c', + ], + dependencies: [ + glib_dep, + gnutls_dep, + ], + include_directories: [ + libvirt_inc, + src_inc_dir, + top_inc_dir, + util_inc_dir, + rpc_inc_dir, + ], + link_args: ( + libvirt_relro + + libvirt_no_indirect + + libvirt_no_undefined + ), + link_with: [ + libvirt_lib + ], install: true, install_dir: bindir, - install_mode: 'rwxr-xr-x', ) =20 executable( diff --git a/tools/virt-pki-validate.c b/tools/virt-pki-validate.c new file mode 100644 index 0000000000..556664dd29 --- /dev/null +++ b/tools/virt-pki-validate.c @@ -0,0 +1,309 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include "internal.h" + +#include +#include +#include + +#include +#include + +#include "virgettext.h" +#include "virfile.h" +#include "virnettlsconfig.h" +#include "virnettlscert.h" +#include "virutil.h" +#include "virt-validate-common.h" + +static bool +virPKIValidateFile(const char *file, + uid_t owner, + gid_t group, + mode_t mode) +{ + struct stat sb; + if (stat(file, &sb) < 0) + return false; + + if (sb.st_uid !=3D owner || + sb.st_gid !=3D group) + return false; + + return (sb.st_mode & 0777) =3D=3D mode; +} + +#define FILE_REQUIRE_EXISTS(scope, path, message, hint, ...) \ + do { \ + virValidateCheck(scope, "%s", message); \ + if (!virFileExists(path)) { \ + virValidateFail(VIR_VALIDATE_FAIL, hint, __VA_ARGS__); \ + ok =3D false; \ + goto done; \ + } else { \ + virValidatePass(); \ + } \ + } while (0) + +#define FILE_REQUIRE_ACCESS(scope, path, message, uid, gid, mode, hint, ..= .) \ + do { \ + virValidateCheck(scope, "%s", message); \ + if (!virPKIValidateFile(path, uid, gid, mode)) { \ + virValidateFail(VIR_VALIDATE_FAIL, hint, __VA_ARGS__); \ + ok =3D false; \ + } else { \ + virValidatePass(); \ + } \ + } while (0) + +static bool +virPKIValidateTrust(void) +{ + g_autofree char *cacert =3D NULL, *cacrl =3D NULL; + bool ok =3D true; + + virNetTLSConfigSystemTrust(&cacert, + &cacrl); + + FILE_REQUIRE_EXISTS("TRUST", + LIBVIRT_PKI_DIR, + _("Checking if system PKI dir exists"), + _("The system PKI dir %1$s is usually installed as= part of the base filesystem or openssl packages"), + LIBVIRT_PKI_DIR); + + FILE_REQUIRE_ACCESS("TRUST", + LIBVIRT_PKI_DIR, + _("Checking system PKI dir access"), + 0, 0, 0755, + _("The system PKI dir %1$s must be accessible to a= ll users. As root, run: chown root.root; chmod 0755 %2$s"), + LIBVIRT_PKI_DIR, LIBVIRT_PKI_DIR); + + + FILE_REQUIRE_EXISTS("TRUST", + LIBVIRT_CACERT_DIR, + _("Checking if system CA dir exists"), + _("The system CA dir %1$s is usually installed as = part of the base filesystem or openssl packages"), + LIBVIRT_CACERT_DIR); + + FILE_REQUIRE_ACCESS("TRUST", + LIBVIRT_CACERT_DIR, + _("Checking system CA dir access"), + 0, 0, 0755, + _("The system CA dir %1$s must be accessible to al= l users. As root, run: chown root.root; chmod 0755 %2$s"), + LIBVIRT_CACERT_DIR, LIBVIRT_CACERT_DIR); + + FILE_REQUIRE_EXISTS("TRUST", + cacert, + _("Checking if CA cert exists"), + _("The machine cannot act as a client or server. S= ee https://libvirt.org/kbase/tlscerts.html#setting-up-a-certificate-authori= ty-ca on how to install %1$s"), + cacert); + + FILE_REQUIRE_ACCESS("TRUST", + cacert, + _("Checking CA cert access"), + 0, 0, 0644, + _("The CA certificate %1$s must be accessible to a= ll users. As root run: chown root.root %2$s; chmod 0644 %3$s"), + cacert, cacert, cacert); + + done: + return ok; +} + +static bool +virPKIValidateIdentity(bool isServer) +{ + g_autofree char *cacert =3D NULL, *cacrl =3D NULL; + g_autofree char *cert =3D NULL, *key =3D NULL; + bool ok =3D true; + const char *scope =3D isServer ? "SERVER" : "CLIENT"; + + virNetTLSConfigSystemTrust(&cacert, + &cacrl); + virNetTLSConfigSystemIdentity(isServer, + &cert, + &key); + + FILE_REQUIRE_EXISTS(scope, + LIBVIRT_CERT_DIR, + _("Checking if system cert dir exists"), + _("The system cert dir %1$s is usually installed a= s part of the libvirt package"), + LIBVIRT_CERT_DIR); + + FILE_REQUIRE_ACCESS(scope, + LIBVIRT_CERT_DIR, + _("Checking system cert dir access"), + 0, 0, 0755, + _("The system cert dir %1$s must be accessible to = all users. As root, run: chown root.root; chmod 0755 %2$s"), + LIBVIRT_PKI_DIR, LIBVIRT_PKI_DIR); + + FILE_REQUIRE_EXISTS(scope, + LIBVIRT_KEY_DIR, + _("Checking if system key dir exists"), + _("The system key dir %1$s is usually installed as= part of the libvirt package"), + LIBVIRT_KEY_DIR); + + FILE_REQUIRE_ACCESS(scope, + LIBVIRT_KEY_DIR, + _("Checking system key dir access"), + 0, 0, 0755, + _("The system key dir %1$s must be accessible to a= ll users. As root, run: chown root.root; chmod 0755 %2$s"), + LIBVIRT_KEY_DIR, LIBVIRT_PKI_DIR); + + FILE_REQUIRE_EXISTS(scope, + key, + _("Checking if key exists"), + isServer ? + _("The machine cannot act as a server. See https:/= /libvirt.org/kbase/tlscerts.html#issuing-server-certificates on how to rege= nerate %1$s") : + _("The machine cannot act as a client. See https:/= /libvirt.org/kbase/tlscerts.html#issuing-client-certificates on how to rege= nerate %1$s"), + key); + + FILE_REQUIRE_ACCESS(scope, + key, + _("Checking key access"), + 0, 0, isServer ? 0600 : 0644, + isServer ? + _("The server key %1$s must not be accessible to u= nprivileged users. As root run: chown root.root %2$s; chmod 0600 %3$s") : + _("The client key %1$s must be accessible to all u= sers. As root run: chown root.root %2$s; chmod 0644 %3$s"), + key, key, key); + + FILE_REQUIRE_EXISTS(scope, + cert, + _("Checking if cert exists"), + isServer ? + _("The machine cannot act as a server. See https:/= /libvirt.org/kbase/tlscerts.html#issuing-server-certificates on how to rege= nerate %1$s") : + _("The machine cannot act as a client. See https:/= /libvirt.org/kbase/tlscerts.html#issuing-client-certificates on how to rege= nerate %1$s"), + cert); + + FILE_REQUIRE_ACCESS(scope, + cert, + _("Checking cert access"), + 0, 0, 0644, + isServer ? + _("The server cert %1$s must be accessible to all = users. As root run: chown root.root %2$s; chmod 0644 %3$s") : + _("The client cert %1$s must be accessible to all = users. As root run: chown root.root %2$s; chmod 0644 %3$s"), + cert, cert, cert); + + virValidateCheck(scope, "%s", _("Checking cert properties")); + + if (virNetTLSCertSanityCheck(isServer, + cacert, + cert) < 0) { + virValidateFail(VIR_VALIDATE_FAIL, "%s", + virGetLastErrorMessage()); + ok =3D false; + } else { + virValidatePass(); + } + + if (isServer) { + gnutls_x509_crt_t crt; + + virValidateCheck(scope, "%s", _("Checking cert hostname match")); + + if (!(crt =3D virNetTLSCertLoadFromFile(cert, true))) { + virValidateFail(VIR_VALIDATE_FAIL, + _("Unable to load %1$s: %2$s"), + cert, virGetLastErrorMessage()); + } else { + g_autofree char *hostname =3D virGetHostname(); + int ret =3D gnutls_x509_crt_check_hostname(crt, hostname); + gnutls_x509_crt_deinit(crt); + if (!ret) { + /* Only warning, since there can be valid reasons for mis-= match */ + virValidateFail(VIR_VALIDATE_WARN, + _("Certificate %1$s owner does not match t= he hostname %2$s"), + cert, hostname); + ok =3D false; + } else { + virValidatePass(); + } + } + } + + done: + return ok; +} + + +static void +print_usage(const char *progname, + FILE *out) +{ + fprintf(out, + _("Usage:\n" + " %1$s { -v | -h } [TRUST|SERVER|CLIENT]\n" + "\n" + "Validate TLS certificate configuration\n" + "\n" + "options:\n" + " -h | --help display this help and exit\n" + " -v | --version output version information and exit\n"), + progname); +} + +int main(int argc, char **argv) +{ + const char *scope =3D NULL; + bool quiet =3D false; + int arg =3D 0; + bool ok =3D true; + const char *progname =3D argv[0]; + struct option opt[] =3D { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 }, + }; + + if (virGettextInitialize() < 0) + return EXIT_FAILURE; + + while ((arg =3D getopt_long(argc, argv, "hvsup:", opt, NULL)) !=3D -1)= { + switch (arg) { + case 'v': + printf("%s\n", PACKAGE_VERSION); + return EXIT_SUCCESS; + + case 'h': + print_usage(progname, stdout); + return EXIT_SUCCESS; + + case 'q': + quiet =3D true; + break; + + case '?': + default: + print_usage(progname, stderr); + return EXIT_FAILURE; + } + } + + if ((argc - optind) > 2) { + fprintf(stderr, _("%1$s: too many command line arguments\n"), argv= [0]); + print_usage(progname, stderr); + return EXIT_FAILURE; + } + + if (argc > 1) + scope =3D argv[optind]; + + virValidateSetQuiet(quiet); + + if ((!scope || g_str_equal(scope, "trust")) && + !virPKIValidateTrust()) + ok =3D false; + if ((!scope || g_str_equal(scope, "server")) && + !virPKIValidateIdentity(true)) + ok =3D false; + if ((!scope || g_str_equal(scope, "client")) && + !virPKIValidateIdentity(false)) + ok =3D false; + + if (!ok) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} diff --git a/tools/virt-pki-validate.in b/tools/virt-pki-validate.in deleted file mode 100644 index c77daa9862..0000000000 --- a/tools/virt-pki-validate.in +++ /dev/null @@ -1,295 +0,0 @@ -#!/bin/sh -# -# This shell script checks the TLS certificates and options needed -# for the secure client/server support of libvirt as documented at -# https://libvirt.org/kbase/tlscerts.html -# -# Copyright (C) 2009-2013 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see -# . -# -# Daniel Veillard -# - -case $1 in - -h | --h | --he | --hel | --help) - cat <&2 - exit 1 ;; -esac - -if test $# !=3D 0; then - echo "$0: unrecognized argument '$1'" >&2 - exit 1 -fi - -USER=3D`who am i | awk '{ print $1 }'` -SERVER=3D1 -CLIENT=3D1 -PORT=3D16514 -# -# First get certtool -# -CERTOOL=3D`which certtool 2>/dev/null` -if [ ! -x "$CERTOOL" ] -then - echo "Could not locate the certtool program" - echo "make sure the gnutls-utils (or gnutls-bin) package is installed" - exit 1 -fi -echo Found "$CERTOOL" - -# -# Check the directory structure -# -SYSCONFDIR=3D"@sysconfdir@" -PKI=3D"$SYSCONFDIR/pki" -if [ ! -d "$PKI" ] -then - echo the $PKI directory is missing, it is usually - echo installed as part of the filesystem or openssl packages - exit 1 -fi - -if [ ! -r "$PKI" ] -then - echo the $PKI directory is not readable by $USER - echo "as root do: chmod a+rx $PKI" - exit 1 -fi -if [ ! -x "$PKI" ] -then - echo the $PKI directory is not listable by $USER - echo "as root do: chmod a+rx $PKI" - exit 1 -fi - -CA=3D"$PKI/CA" -if [ ! -d "$CA" ] -then - echo the $CA directory is missing, it is usually - echo installed as part of the or openssl package - exit 1 -fi - -if [ ! -r "$CA" ] -then - echo the $CA directory is not readable by $USER - echo "as root do: chmod a+rx $CA" - exit 1 -fi -if [ ! -x "$CA" ] -then - echo the $CA directory is not listable by $USER - echo "as root do: chmod a+rx $CA" - exit 1 -fi - -LIBVIRT=3D"$PKI/libvirt" -if [ ! -d "$LIBVIRT" ] -then - echo the $LIBVIRT directory is missing, it is usually - echo installed by the libvirt package - echo "as root do: mkdir -m 755 $LIBVIRT ; chown root:root $LIBVIRT" - exit 1 -fi - -if [ ! -r "$LIBVIRT" ] -then - echo the $LIBVIRT directory is not readable by $USER - echo "as root do: chown root:root $LIBVIRT ; chmod 755 $LIBVIRT" - exit 1 -fi -if [ ! -x "$LIBVIRT" ] -then - echo the $LIBVIRT directory is not listable by $USER - echo "as root do: chown root:root $LIBVIRT ; chmod 755 $LIBVIRT" - exit 1 -fi - -LIBVIRTP=3D"$LIBVIRT/private" -if [ ! -d "$LIBVIRTP" ] -then - echo the $LIBVIRTP directory is missing, it is usually - echo installed by the libvirt package - echo "as root do: mkdir -m 755 $LIBVIRTP ; chown root:root $LIBVIRTP" - exit 1 -fi - -if [ ! -r "$LIBVIRTP" ] -then - echo the $LIBVIRTP directory is not readable by $USER - echo "as root do: chown root:root $LIBVIRTP ; chmod 755 $LIBVIRTP" - exit 1 -fi -if [ ! -x "$LIBVIRTP" ] -then - echo the $LIBVIRTP directory is not listable by $USER - echo "as root do: chown root:root $LIBVIRTP ; chmod 755 $LIBVIRTP" - exit 1 -fi - -# -# Now check the certificates -# First the CA certificate -# -if [ ! -f "$CA/cacert.pem" ] -then - echo the CA certificate $CA/cacert.pem is missing while it - echo should be installed on both client and servers - echo "see https://libvirt.org/kbase/tlscerts.html#setting-up-a-certifi= cate-authority-ca" - echo on how to install it - exit 1 -fi -if [ ! -r "$CA/cacert.pem" ] -then - echo the CA certificate $CA/cacert.pem is not readable by $USER - echo "as root do: chmod 644 $CA/cacert.pem" - exit 1 -fi -sed_get_org=3D'/Issuer:/ { - s/.*Issuer:.*CN=3D// - s/,.*// - p -}' -ORG=3D`"$CERTOOL" -i --infile "$CA/cacert.pem" | sed -n "$sed_get_org"` -if [ "$ORG" =3D "" ] -then - echo the CA certificate $CA/cacert.pem does not define the organization - echo it should probably regenerated - echo "see https://libvirt.org/kbase/tlscerts.html#setting-up-a-certifi= cate-authority-ca" - echo on how to regenerate it - exit 1 -fi -echo Found CA certificate $CA/cacert.pem for $ORG - -# Second the client certificates - -if [ -f "$LIBVIRT/clientcert.pem" ] -then - if [ ! -r "$LIBVIRT/clientcert.pem" ] - then - echo Client certificate $LIBVIRT/clientcert.pem should be world re= adable - echo "as root do: chown root:root $LIBVIRT/clientcert.pem ; chmod = 644 $LIBVIRT/clientcert.pem" - else - C_ORG=3D`"$CERTOOL" -i --infile "$LIBVIRT/clientcert.pem" | grep S= ubject: | sed 's+.*O=3D\([^,]*\).*+\1+'` - if [ "$ORG" !=3D "$C_ORG" ] - then - echo The CA certificate and the client certificate do not match - echo CA organization: $ORG - echo Client organization: $C_ORG - fi - CLIENT=3D`"$CERTOOL" -i --infile "$LIBVIRT/clientcert.pem" | grep = Subject: | sed 's+.*CN=3D\(.[^,]*\).*+\1+'` - echo Found client certificate $LIBVIRT/clientcert.pem for $CLIENT - if [ ! -e "$LIBVIRTP/clientkey.pem" ] - then - echo Missing client private key $LIBVIRTP/clientkey.pem - else - echo Found client private key $LIBVIRTP/clientkey.pem - OWN=3D`ls -l "$LIBVIRTP/clientkey.pem" | awk '{ print $3 }'` - # The substr($1, 1, 10) gets rid of acl and xattr markers - MOD=3D`ls -l "$LIBVIRTP/clientkey.pem" | awk '{ print substr($= 1, 1, 10) }'` - if [ "$OWN" !=3D "root" ] - then - echo The client private key should be owned by root - echo "as root do: chown root $LIBVIRTP/clientkey.pem" - fi - if [ "$MOD" !=3D "-rw-r--r--" ] - then - echo The client private key need to be read by client tools - echo "as root do: chmod 644 $LIBVIRTP/clientkey.pem" - fi - fi - - fi -else - echo Did not find "$LIBVIRT/clientcert.pem" client certificate - echo The machine cannot act as a client - echo "see https://libvirt.org/kbase/tlscerts.html#issuing-client-certi= ficates" - echo on how to regenerate it - CLIENT=3D0 -fi - -# Third the server certificates - -if [ -f "$LIBVIRT/servercert.pem" ] -then - if [ ! -r "$LIBVIRT/servercert.pem" ] - then - echo Server certificate $LIBVIRT/servercert.pem should be world re= adable - echo "as root do: chown root:root $LIBVIRT/servercert.pem ; chmod = 644 $LIBVIRT/servercert.pem" - else - S_ORG=3D`"$CERTOOL" -i --infile "$LIBVIRT/servercert.pem" | grep S= ubject: | sed 's+.*O=3D\([^,]*\).*+\1+'` - if [ "$ORG" !=3D "$S_ORG" ] - then - echo The CA certificate and the server certificate do not match - echo CA organization: $ORG - echo Server organization: $S_ORG - fi - S_HOST=3D`"$CERTOOL" -i --infile "$LIBVIRT/servercert.pem" | grep = Subject: | sed 's+.*CN=3D\([^,]*\).*+\1+'` - if test "$S_HOST" !=3D "`hostname -s`" && test "$S_HOST" !=3D "`ho= stname`" - then - echo The server certificate does not seem to match the host na= me - echo hostname: '"'`hostname`'"' - echo Server certificate CN: '"'$S_HOST'"' - fi - echo Found server certificate $LIBVIRT/servercert.pem for $S_HOST - if [ ! -e "$LIBVIRTP/serverkey.pem" ] - then - echo Missing server private key $LIBVIRTP/serverkey.pem - else - echo Found server private key $LIBVIRTP/serverkey.pem - OWN=3D`ls -l "$LIBVIRTP/serverkey.pem" | awk '{ print $3 }'` - # The substr($1, 1, 10) gets rid of acl and xattr markers - MOD=3D`ls -l "$LIBVIRTP/serverkey.pem" | awk '{ print substr($= 1, 1, 10) }'` - if [ "$OWN" !=3D "root" ] - then - echo The server private key should be owned by root - echo "as root do: chown root $LIBVIRTP/serverkey.pem" - fi - if [ "$MOD" !=3D "-rw-------" ] - then - echo The server private key need to be read only by root - echo "as root do: chmod 600 $LIBVIRTP/serverkey.pem" - fi - fi - - fi -else - echo Did not find $LIBVIRT/servercert.pem server certificate - echo The machine cannot act as a server - echo "see https://libvirt.org/kbase/tlscerts.html#issuing-server-certi= ficates" - echo on how to regenerate it - SERVER=3D0 -fi - -exit 0 --=20 2.43.0 From nobody Mon Sep 16 19:15:09 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) client-ip=8.43.85.245; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 8.43.85.245 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [8.43.85.245]) by mx.zohomail.com with SMTPS id 1717771360730788.8551569741996; Fri, 7 Jun 2024 07:42:40 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 996) id C801E25DB; Fri, 7 Jun 2024 10:42:38 -0400 (EDT) Received: from lists.libvirt.org (localhost [IPv6:::1]) by lists.libvirt.org (Postfix) with ESMTP id 4C7DA259E; Fri, 7 Jun 2024 10:40:02 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 996) id 9FC5B24A8; Fri, 7 Jun 2024 10:39:58 -0400 (EDT) Received: from mx1.osci.io (polly.osci.io [8.43.85.229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 042A02485 for ; Fri, 7 Jun 2024 10:39:53 -0400 (EDT) Received: by mx1.osci.io (Postfix, from userid 994) id E553F2254B; Fri, 7 Jun 2024 10:39:52 -0400 (EDT) Received: from mx3.osci.io (carla.osci.io [IPv6:2607:f0d0:1e02:35::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits)) (No client certificate requested) by mx1.osci.io (Postfix) with ESMTPS id E8CCA22467 for ; Fri, 7 Jun 2024 10:39:45 -0400 (EDT) Received: by mx3.osci.io (Postfix, from userid 990) id CE8F730721D2; Fri, 7 Jun 2024 09:33:02 -0500 (CDT) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by mx3.osci.io (Postfix) with ESMTPS id 9FF3C30721D9 for ; Fri, 7 Jun 2024 09:33:00 -0500 (CDT) Received: from mimecast-mx02.redhat.com (mx-ext.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-47-T6RziESNN6epp4A_bPFM6A-1; Fri, 07 Jun 2024 10:26:25 -0400 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 4C9DE3806706 for ; Fri, 7 Jun 2024 14:26:25 +0000 (UTC) Received: from toolbox.redhat.com (unknown [10.39.193.232]) by smtp.corp.redhat.com (Postfix) with ESMTP id C4967492BC6; Fri, 7 Jun 2024 14:26:24 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-0.6 required=5.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.4 X-Greylist: delayed 375 seconds by postgrey-1.37 at polly.osci.io; Fri, 07 Jun 2024 10:39:45 EDT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770387; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MbNl9jAhJpt8YD9GrbpFCfJGtKzMTGQZ73/hbZBE970=; b=J8Dlz8goDoNdMdPdVrY95PkiaJcGnLzWobpLMPKtlnUT90MvRmBOr8+wfyTcQFGA4BE0LH k6b9Efl0+jfzWWSmMTyDR/1rRQ2h9R+aINNdOv3J9FRNsrPaYA9I4RtEBm/GwRqn7ji/CB 61VNWZZS5G+q5P/rJoqBe6VkfCVxUaQ= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770517; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MbNl9jAhJpt8YD9GrbpFCfJGtKzMTGQZ73/hbZBE970=; b=bnXKx9Ftdt+TbwCCDhWXMz6lf38QwgFw/fnhHNE1VFwu9eHuAEz/41l+w7v6PHquxE6EiO ymvfHAEiB6PK/aoprhk61oY+eyOdnnfO9+/dstspwM99jNJffmXWmvAQooGGQNhunDVUsJ p6bV6y0ABiyyJxGlpXHwt82dRioXCcM= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770648; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MbNl9jAhJpt8YD9GrbpFCfJGtKzMTGQZ73/hbZBE970=; b=CcoCUEyYjIk5lp0X5qn6kXf9Cb6GdqQRoNAi8njQq2xOCFrVo6xYWTLIUPZh5+GgCSBTHL 1+2BbYoEARFWNGSyW0aBfQxK/9Z7cdES+CbrRyPI/WdCC8fOgVTwGHdEmg7zHcNF1RWN6E Zr/AEfOHbmptLFKr7cvJnU58VSgmsVs= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1717770780; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MbNl9jAhJpt8YD9GrbpFCfJGtKzMTGQZ73/hbZBE970=; b=dOY/RJc814JKkQWRlkM2hYDm4cbHJUR/erExelRKkKTTWWuZR2CV4U6jVv5t1pA1Z056LC LudGBCvLWrJwKCm1moHuVmzO0iWf3fIEolAOb0Jeu7j5uDULfAbmRldLcEUhOOiyCm+kFI hVmAllBtoOrUJKz4n0igtezkdCJG44M= X-MC-Unique: T6RziESNN6epp4A_bPFM6A-1 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: devel@lists.libvirt.org Cc: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Subject: [PATCH 9/9] tools: support validating user/custom PKI certs Date: Fri, 7 Jun 2024 15:26:16 +0100 Message-ID: <20240607142616.749339-10-berrange@redhat.com> In-Reply-To: <20240607142616.749339-1-berrange@redhat.com> References: <20240607142616.749339-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.9 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable Message-ID-Hash: H2MF2655UTB6Y62M5J3QREKDEU44KFWH X-Message-ID-Hash: H2MF2655UTB6Y62M5J3QREKDEU44KFWH X-MailFrom: SRS0=RZ0v=NJ=redhat.com=berrange@osci.io X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-config-1; header-match-config-2; header-match-config-3; header-match-devel.lists.libvirt.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.2 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-ZohoMail-DKIM: fail (found 4 invalid signatures) X-ZM-MESSAGEID: 1717771361879100001 Content-Type: text/plain; charset="utf-8" The virt-pki-validate command can validate the system certificate directories. The remote driver, however, also supports a standard per-user certs location, as well as a runtime custom path. This extends the validation tool to be able to cope with these alternate locations too. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Michal Privoznik --- docs/manpages/virt-pki-validate.rst | 5 +- tools/virt-pki-validate.c | 289 +++++++++++++++++++--------- 2 files changed, 206 insertions(+), 88 deletions(-) diff --git a/docs/manpages/virt-pki-validate.rst b/docs/manpages/virt-pki-v= alidate.rst index cf17bad790..932c677cfc 100644 --- a/docs/manpages/virt-pki-validate.rst +++ b/docs/manpages/virt-pki-validate.rst @@ -15,7 +15,7 @@ SYNOPSIS =3D=3D=3D=3D=3D=3D=3D=3D =20 =20 -``virt-pki-validate`` [*OPTION*] +``virt-pki-validate`` [*OPTION*] [trust|server|client] =20 =20 DESCRIPTION @@ -26,6 +26,9 @@ a secure libvirt server or client using the TLS encryptio= n protocol. It will report any missing certificate or key files on the host. It should be run as root to ensure it can read all the necessary files =20 +With no arguments it will check the trusted CA config, the server +config and the client config. The optional positional argument can +be used to restrict the checks to just one of these three sets. =20 OPTIONS =3D=3D=3D=3D=3D=3D=3D diff --git a/tools/virt-pki-validate.c b/tools/virt-pki-validate.c index 556664dd29..656f29fdc5 100644 --- a/tools/virt-pki-validate.c +++ b/tools/virt-pki-validate.c @@ -60,40 +60,77 @@ virPKIValidateFile(const char *file, } while (0) =20 static bool -virPKIValidateTrust(void) +virPKIValidateTrust(bool system, const char *path) { g_autofree char *cacert =3D NULL, *cacrl =3D NULL; bool ok =3D true; =20 - virNetTLSConfigSystemTrust(&cacert, - &cacrl); - - FILE_REQUIRE_EXISTS("TRUST", - LIBVIRT_PKI_DIR, - _("Checking if system PKI dir exists"), - _("The system PKI dir %1$s is usually installed as= part of the base filesystem or openssl packages"), - LIBVIRT_PKI_DIR); - - FILE_REQUIRE_ACCESS("TRUST", - LIBVIRT_PKI_DIR, - _("Checking system PKI dir access"), - 0, 0, 0755, - _("The system PKI dir %1$s must be accessible to a= ll users. As root, run: chown root.root; chmod 0755 %2$s"), - LIBVIRT_PKI_DIR, LIBVIRT_PKI_DIR); - - - FILE_REQUIRE_EXISTS("TRUST", - LIBVIRT_CACERT_DIR, - _("Checking if system CA dir exists"), - _("The system CA dir %1$s is usually installed as = part of the base filesystem or openssl packages"), - LIBVIRT_CACERT_DIR); - - FILE_REQUIRE_ACCESS("TRUST", - LIBVIRT_CACERT_DIR, - _("Checking system CA dir access"), - 0, 0, 0755, - _("The system CA dir %1$s must be accessible to al= l users. As root, run: chown root.root; chmod 0755 %2$s"), - LIBVIRT_CACERT_DIR, LIBVIRT_CACERT_DIR); + if (system) { + virNetTLSConfigSystemTrust(&cacert, + &cacrl); + + FILE_REQUIRE_EXISTS("TRUST", + LIBVIRT_PKI_DIR, + _("Checking if system PKI dir exists"), + _("The system PKI dir %1$s is usually installe= d as part of the base filesystem or openssl packages"), + LIBVIRT_PKI_DIR); + + FILE_REQUIRE_ACCESS("TRUST", + LIBVIRT_PKI_DIR, + _("Checking system PKI dir access"), + 0, 0, 0755, + _("The system PKI dir %1$s must be accessible = to all users. As root, run: chown root.root; chmod 0755 %2$s"), + LIBVIRT_PKI_DIR, LIBVIRT_PKI_DIR); + + + FILE_REQUIRE_EXISTS("TRUST", + LIBVIRT_CACERT_DIR, + _("Checking if system CA dir exists"), + _("The system CA dir %1$s is usually installed= as part of the base filesystem or openssl packages"), + LIBVIRT_CACERT_DIR); + + FILE_REQUIRE_ACCESS("TRUST", + LIBVIRT_CACERT_DIR, + _("Checking system CA dir access"), + 0, 0, 0755, + _("The system CA dir %1$s must be accessible t= o all users. As root, run: chown root.root; chmod 0755 %2$s"), + LIBVIRT_CACERT_DIR, LIBVIRT_CACERT_DIR); + } else if (path) { + virNetTLSConfigCustomTrust(path, + &cacert, + &cacrl); + + FILE_REQUIRE_EXISTS("TRUST", + path, + _("Checking if custom PKI base dir exists"), + _("Create the dir %1$s"), + path); + + FILE_REQUIRE_ACCESS("TRUST", + path, + _("Checking custom PKI base dir access"), + getuid(), getgid(), 0700, + _("The PKI base dir %1$s must not be accessibl= e to other users. Run: chown %2$d.%3$d %4$s; chmod 0700 %5$s"), + path, getuid(), getgid(), path, path); + } else { + g_autofree char *pkipath =3D virNetTLSConfigUserPKIBaseDir(); + + virNetTLSConfigUserTrust(&cacert, + &cacrl); + + FILE_REQUIRE_EXISTS("TRUST", + pkipath, + _("Checking if user PKI base dir exists"), + _("Create the dir %1$s"), + pkipath); + + FILE_REQUIRE_ACCESS("TRUST", + pkipath, + _("Checking user PKI base dir access"), + getuid(), getgid(), 0700, + _("The PKI base dir %1$s must not be accessibl= e to other users. Run: chown %2$d.%3$d %4$s; chmod 0700 %5$s"), + pkipath, getuid(), getgid(), pkipath, pkipath); + } =20 FILE_REQUIRE_EXISTS("TRUST", cacert, @@ -101,56 +138,81 @@ virPKIValidateTrust(void) _("The machine cannot act as a client or server. S= ee https://libvirt.org/kbase/tlscerts.html#setting-up-a-certificate-authori= ty-ca on how to install %1$s"), cacert); =20 - FILE_REQUIRE_ACCESS("TRUST", - cacert, - _("Checking CA cert access"), - 0, 0, 0644, - _("The CA certificate %1$s must be accessible to a= ll users. As root run: chown root.root %2$s; chmod 0644 %3$s"), - cacert, cacert, cacert); + if (system) { + FILE_REQUIRE_ACCESS("TRUST", + cacert, + _("Checking CA cert access"), + 0, 0, 0644, + _("The CA certificate %1$s must be accessible = to all users. As root run: chown root.root %2$s; chmod 0644 %3$s"), + cacert, cacert, cacert); + } else { + FILE_REQUIRE_ACCESS("TRUST", + cacert, + _("Checking CA cert access"), + getuid(), getgid(), 0600, + _("The CA certificate %1$s must not be accessi= ble to other users. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$= s"), + cacert, getuid(), getgid(), cacert, cacert); + } =20 done: return ok; } =20 static bool -virPKIValidateIdentity(bool isServer) +virPKIValidateIdentity(bool isServer, bool system, const char *path) { g_autofree char *cacert =3D NULL, *cacrl =3D NULL; g_autofree char *cert =3D NULL, *key =3D NULL; bool ok =3D true; const char *scope =3D isServer ? "SERVER" : "CLIENT"; =20 - virNetTLSConfigSystemTrust(&cacert, - &cacrl); - virNetTLSConfigSystemIdentity(isServer, - &cert, - &key); - - FILE_REQUIRE_EXISTS(scope, - LIBVIRT_CERT_DIR, - _("Checking if system cert dir exists"), - _("The system cert dir %1$s is usually installed a= s part of the libvirt package"), - LIBVIRT_CERT_DIR); - - FILE_REQUIRE_ACCESS(scope, - LIBVIRT_CERT_DIR, - _("Checking system cert dir access"), - 0, 0, 0755, - _("The system cert dir %1$s must be accessible to = all users. As root, run: chown root.root; chmod 0755 %2$s"), - LIBVIRT_PKI_DIR, LIBVIRT_PKI_DIR); - - FILE_REQUIRE_EXISTS(scope, - LIBVIRT_KEY_DIR, - _("Checking if system key dir exists"), - _("The system key dir %1$s is usually installed as= part of the libvirt package"), - LIBVIRT_KEY_DIR); - - FILE_REQUIRE_ACCESS(scope, - LIBVIRT_KEY_DIR, - _("Checking system key dir access"), - 0, 0, 0755, - _("The system key dir %1$s must be accessible to a= ll users. As root, run: chown root.root; chmod 0755 %2$s"), - LIBVIRT_KEY_DIR, LIBVIRT_PKI_DIR); + if (system) { + virNetTLSConfigSystemTrust(&cacert, + &cacrl); + virNetTLSConfigSystemIdentity(isServer, + &cert, + &key); + + FILE_REQUIRE_EXISTS(scope, + LIBVIRT_CERT_DIR, + _("Checking if system cert dir exists"), + _("The system cert dir %1$s is usually install= ed as part of the libvirt package"), + LIBVIRT_CERT_DIR); + + FILE_REQUIRE_ACCESS(scope, + LIBVIRT_CERT_DIR, + _("Checking system cert dir access"), + 0, 0, 0755, + _("The system cert dir %1$s must be accessible= to all users. As root, run: chown root.root; chmod 0755 %2$s"), + LIBVIRT_PKI_DIR, LIBVIRT_PKI_DIR); + + FILE_REQUIRE_EXISTS(scope, + LIBVIRT_KEY_DIR, + _("Checking if system key dir exists"), + _("The system key dir %1$s is usually installe= d as part of the libvirt package"), + LIBVIRT_KEY_DIR); + + FILE_REQUIRE_ACCESS(scope, + LIBVIRT_KEY_DIR, + _("Checking system key dir access"), + 0, 0, 0755, + _("The system key dir %1$s must be accessible = to all users. As root, run: chown root.root; chmod 0755 %2$s"), + LIBVIRT_KEY_DIR, LIBVIRT_PKI_DIR); + } else if (path) { + virNetTLSConfigCustomTrust(path, + &cacert, + &cacrl); + virNetTLSConfigCustomIdentity(path, + isServer, + &cert, + &key); + } else { + virNetTLSConfigUserTrust(&cacert, + &cacrl); + virNetTLSConfigUserIdentity(isServer, + &cert, + &key); + } =20 FILE_REQUIRE_EXISTS(scope, key, @@ -160,14 +222,25 @@ virPKIValidateIdentity(bool isServer) _("The machine cannot act as a client. See https:/= /libvirt.org/kbase/tlscerts.html#issuing-client-certificates on how to rege= nerate %1$s"), key); =20 - FILE_REQUIRE_ACCESS(scope, - key, - _("Checking key access"), - 0, 0, isServer ? 0600 : 0644, - isServer ? - _("The server key %1$s must not be accessible to u= nprivileged users. As root run: chown root.root %2$s; chmod 0600 %3$s") : - _("The client key %1$s must be accessible to all u= sers. As root run: chown root.root %2$s; chmod 0644 %3$s"), - key, key, key); + if (system) { + FILE_REQUIRE_ACCESS(scope, + key, + _("Checking key access"), + 0, 0, isServer ? 0600 : 0644, + isServer ? + _("The server key %1$s must not be accessible = to unprivileged users. As root run: chown root.root %2$s; chmod 0600 %3$s")= : + _("The client key %1$s must be accessible to a= ll users. As root run: chown root.root %2$s; chmod 0644 %3$s"), + key, key, key); + } else { + FILE_REQUIRE_ACCESS(scope, + key, + _("Checking key access"), + getuid(), getgid(), 0600, + isServer ? + _("The server key %1$s must be not be accessib= le to other users. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s= ") : + _("The client key %1$s must be not be accessib= le to other users. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s= "), + key, getuid(), getgid(), key, key); + } =20 FILE_REQUIRE_EXISTS(scope, cert, @@ -177,14 +250,25 @@ virPKIValidateIdentity(bool isServer) _("The machine cannot act as a client. See https:/= /libvirt.org/kbase/tlscerts.html#issuing-client-certificates on how to rege= nerate %1$s"), cert); =20 - FILE_REQUIRE_ACCESS(scope, - cert, - _("Checking cert access"), - 0, 0, 0644, - isServer ? - _("The server cert %1$s must be accessible to all = users. As root run: chown root.root %2$s; chmod 0644 %3$s") : - _("The client cert %1$s must be accessible to all = users. As root run: chown root.root %2$s; chmod 0644 %3$s"), - cert, cert, cert); + if (system) { + FILE_REQUIRE_ACCESS(scope, + cert, + _("Checking cert access"), + 0, 0, 0644, + isServer ? + _("The server cert %1$s must be accessible to = all users. As root run: chown root.root %2$s; chmod 0644 %3$s") : + _("The client cert %1$s must be accessible to = all users. As root run: chown root.root %2$s; chmod 0644 %3$s"), + cert, cert, cert); + } else { + FILE_REQUIRE_ACCESS(scope, + cert, + _("Checking cert access"), + getuid(), getgid(), 0600, + isServer ? + _("The server cert %1$s must be restricted to = this user. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s") : + _("The client cert %1$s must be restricted to = this user. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s"), + cert, getuid(), getgid(), cert, cert); + } =20 virValidateCheck(scope, "%s", _("Checking cert properties")); =20 @@ -239,6 +323,9 @@ print_usage(const char *progname, "Validate TLS certificate configuration\n" "\n" "options:\n" + " -s | --system validate system certificates (default)\= n" + " -u | --user validate user certificates\n" + " -p DIR | --path DIR validate custom certificate path\n" " -h | --help display this help and exit\n" " -v | --version output version information and exit\n"), progname); @@ -247,6 +334,9 @@ print_usage(const char *progname, int main(int argc, char **argv) { const char *scope =3D NULL; + bool system =3D false; + bool user =3D false; + const char *path =3D NULL; bool quiet =3D false; int arg =3D 0; bool ok =3D true; @@ -254,6 +344,9 @@ int main(int argc, char **argv) struct option opt[] =3D { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, + { "system", no_argument, NULL, 's' }, + { "user", no_argument, NULL, 'u' }, + { "path", required_argument, NULL, 'p' }, { NULL, 0, NULL, 0 }, }; =20 @@ -262,6 +355,18 @@ int main(int argc, char **argv) =20 while ((arg =3D getopt_long(argc, argv, "hvsup:", opt, NULL)) !=3D -1)= { switch (arg) { + case 's': + system =3D true; + break; + + case 'u': + user =3D true; + break; + + case 'p': + path =3D optarg; + break; + case 'v': printf("%s\n", PACKAGE_VERSION); return EXIT_SUCCESS; @@ -292,14 +397,24 @@ int main(int argc, char **argv) =20 virValidateSetQuiet(quiet); =20 + if ((system && user) || + (system && path) || + (user && path)) { + g_printerr("--system, --user & --path are mutually exclusive\n"); + return EXIT_FAILURE; + } + + if (!system && !user && !path) + system =3D true; + if ((!scope || g_str_equal(scope, "trust")) && - !virPKIValidateTrust()) + !virPKIValidateTrust(system, path)) ok =3D false; if ((!scope || g_str_equal(scope, "server")) && - !virPKIValidateIdentity(true)) + !virPKIValidateIdentity(true, system, path)) ok =3D false; if ((!scope || g_str_equal(scope, "client")) && - !virPKIValidateIdentity(false)) + !virPKIValidateIdentity(false, system, path)) ok =3D false; =20 if (!ok) --=20 2.43.0