winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

AdminSettings.cpp (17026B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "AppInstallerLogging.h"
      5 #include "AppInstallerStrings.h"
      6 #include "winget/Settings.h"
      7 #include "winget/AdminSettings.h"
      8 #include "winget/GroupPolicy.h"
      9 #include "winget/Yaml.h"
     10 
     11 namespace AppInstaller::Settings
     12 {
     13     using namespace std::string_view_literals;
     14     using namespace Utility::literals;
     15 
     16     namespace
     17     {
     18         constexpr Utility::LocIndView s_AdminSettingsYaml_LocalManifestFiles = "LocalManifestFiles"_liv;
     19         constexpr Utility::LocIndView s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore = "BypassCertificatePinningForMicrosoftStore"_liv;
     20         constexpr Utility::LocIndView s_AdminSettingsYaml_InstallerHashOverride = "InstallerHashOverride"_liv;
     21         constexpr Utility::LocIndView s_AdminSettingsYaml_LocalArchiveMalwareScanOverride = "LocalArchiveMalwareScanOverride"_liv;
     22         constexpr Utility::LocIndView s_AdminSettingsYaml_ProxyCommandLineOptions = "ProxyCommandLineOptions"_liv;
     23 
     24         constexpr Utility::LocIndView s_AdminSettingsYaml_DefaultProxy = "DefaultProxy"_liv;
     25 
     26         // Attempts to read a single scalar value from the node.
     27         template<typename Value>
     28         bool TryReadScalar(const YAML::Node& rootNode, std::string_view name, Value& value)
     29         {
     30             YAML::Node valueNode = rootNode[std::string{ name }];
     31 
     32             if (!valueNode || !valueNode.IsScalar())
     33             {
     34                 AICLI_LOG(Core, Verbose, << "Admin setting '" << name << "' was not found or did not contain the expected format");
     35                 return false;
     36             }
     37 
     38             value = valueNode.as<Value>();
     39             return true;
     40         }
     41 
     42         struct AdminSettingValues
     43         {
     44             bool LocalManifestFiles = false;
     45             bool BypassCertificatePinningForMicrosoftStore = false;
     46             bool InstallerHashOverride = false;
     47             bool LocalArchiveMalwareScanOverride = false;
     48             bool ProxyCommandLineOptions = false;
     49 
     50             std::optional<std::string> DefaultProxy;
     51         };
     52 
     53         struct AdminSettingsInternal
     54         {
     55             AdminSettingsInternal();
     56 
     57             void SetAdminSetting(BoolAdminSetting setting, bool enabled);
     58             void SetAdminSetting(StringAdminSetting setting, const std::optional<std::string>& value);
     59 
     60             bool GetAdminSettingValue(BoolAdminSetting setting) const;
     61             std::optional<std::string> GetAdminSettingValue(StringAdminSetting setting) const;
     62 
     63             void Reset();
     64 
     65         private:
     66             void LoadAdminSettings();
     67             [[nodiscard]] bool SaveAdminSettings();
     68 
     69             // Sets the value of an admin setting using the given function and then saves the changes.
     70             // Encapsulates the retry and reload logic.
     71             // Stops if the value cannot be set, as indicated by the return value of setValue()
     72             void SetAdminSettingAndSave(std::function<bool()> setValue);
     73 
     74             Stream m_settingStream;
     75             AdminSettingValues m_settingValues;
     76         };
     77 
     78         AdminSettingsInternal::AdminSettingsInternal() : m_settingStream(Stream::AdminSettings)
     79         {
     80             LoadAdminSettings();
     81         }
     82 
     83         void AdminSettingsInternal::SetAdminSettingAndSave(std::function<bool()> setValue)
     84         {
     85             for (size_t i = 0; i < 10; ++i)
     86             {
     87                 if (!setValue())
     88                 {
     89                     return;
     90                 }
     91 
     92                 if (SaveAdminSettings())
     93                 {
     94                     return;
     95                 }
     96 
     97                 // We need to reload the settings as they have changed
     98                 LoadAdminSettings();
     99             }
    100 
    101             THROW_HR_MSG(E_UNEXPECTED, "Too many attempts at SaveAdminSettings");
    102         }
    103 
    104         void AdminSettingsInternal::SetAdminSetting(BoolAdminSetting setting, bool enabled)
    105         {
    106             SetAdminSettingAndSave([&]()
    107                 {
    108                     switch (setting)
    109                     {
    110                     case BoolAdminSetting::LocalManifestFiles:
    111                         m_settingValues.LocalManifestFiles = enabled;
    112                         return true;
    113                     case BoolAdminSetting::BypassCertificatePinningForMicrosoftStore:
    114                         m_settingValues.BypassCertificatePinningForMicrosoftStore = enabled;
    115                         return true;
    116                     case BoolAdminSetting::InstallerHashOverride:
    117                         m_settingValues.InstallerHashOverride = enabled;
    118                         return true;
    119                     case BoolAdminSetting::LocalArchiveMalwareScanOverride:
    120                         m_settingValues.LocalArchiveMalwareScanOverride = enabled;
    121                         return true;
    122                     case BoolAdminSetting::ProxyCommandLineOptions:
    123                         m_settingValues.ProxyCommandLineOptions = enabled;
    124                         return true;
    125                     default:
    126                         return false;
    127                     }
    128                 });
    129         }
    130 
    131         void AdminSettingsInternal::SetAdminSetting(StringAdminSetting setting, const std::optional<std::string>& value)
    132         {
    133             SetAdminSettingAndSave([&]()
    134                 {
    135                     switch (setting)
    136                     {
    137                     case StringAdminSetting::DefaultProxy:
    138                         m_settingValues.DefaultProxy = value;
    139                         return true;
    140                     default:
    141                         return false;
    142                     }
    143                 });
    144         }
    145 
    146         bool AdminSettingsInternal::GetAdminSettingValue(BoolAdminSetting setting) const
    147         {
    148             switch (setting)
    149             {
    150             case BoolAdminSetting::LocalManifestFiles:
    151                 return m_settingValues.LocalManifestFiles;
    152             case BoolAdminSetting::BypassCertificatePinningForMicrosoftStore:
    153                 return m_settingValues.BypassCertificatePinningForMicrosoftStore;
    154             case BoolAdminSetting::InstallerHashOverride:
    155                 return m_settingValues.InstallerHashOverride;
    156             case BoolAdminSetting::LocalArchiveMalwareScanOverride:
    157                 return m_settingValues.LocalArchiveMalwareScanOverride;
    158             case BoolAdminSetting::ProxyCommandLineOptions:
    159                 return m_settingValues.ProxyCommandLineOptions;
    160             default:
    161                 return false;
    162             }
    163         }
    164 
    165         std::optional<std::string> AdminSettingsInternal::GetAdminSettingValue(StringAdminSetting setting) const
    166         {
    167             switch (setting)
    168             {
    169             case StringAdminSetting::DefaultProxy:
    170                 return m_settingValues.DefaultProxy;
    171             default:
    172                 return std::nullopt;
    173             }
    174         }
    175 
    176         void AdminSettingsInternal::Reset()
    177         {
    178             m_settingStream.Remove();
    179         }
    180 
    181         void AdminSettingsInternal::LoadAdminSettings()
    182         {
    183             auto stream = m_settingStream.Get();
    184             if (!stream)
    185             {
    186                 AICLI_LOG(Core, Verbose, << "Admin settings was not found");
    187                 return;
    188             }
    189 
    190             std::string adminSettingsYaml = Utility::ReadEntireStream(*stream);
    191 
    192             YAML::Node document;
    193             try
    194             {
    195                 document = YAML::Load(adminSettingsYaml);
    196             }
    197             catch (const std::exception& e)
    198             {
    199                 AICLI_LOG(YAML, Error, << "Admin settings contained invalid YAML (" << e.what() << ")");
    200                 return;
    201             }
    202 
    203             if (document.IsNull())
    204             {
    205                 AICLI_LOG(Core, Info, << "Admin settings is empty");
    206                 return;
    207             }
    208 
    209             if (!document.IsMap())
    210             {
    211                 AICLI_LOG(Core, Error, << "Admin settings did not contain the expected format");
    212                 return;
    213             }
    214 
    215             TryReadScalar<bool>(document, s_AdminSettingsYaml_LocalManifestFiles, m_settingValues.LocalManifestFiles);
    216             TryReadScalar<bool>(document, s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore, m_settingValues.BypassCertificatePinningForMicrosoftStore);
    217             TryReadScalar<bool>(document, s_AdminSettingsYaml_InstallerHashOverride, m_settingValues.InstallerHashOverride);
    218             TryReadScalar<bool>(document, s_AdminSettingsYaml_LocalArchiveMalwareScanOverride, m_settingValues.LocalArchiveMalwareScanOverride);
    219             TryReadScalar<bool>(document, s_AdminSettingsYaml_ProxyCommandLineOptions, m_settingValues.ProxyCommandLineOptions);
    220 
    221             std::string defaultProxy;
    222             if (TryReadScalar<std::string>(document, s_AdminSettingsYaml_DefaultProxy, defaultProxy))
    223             {
    224                 m_settingValues.DefaultProxy.emplace(std::move(defaultProxy));
    225             }
    226         }
    227 
    228         bool AdminSettingsInternal::SaveAdminSettings()
    229         {
    230             YAML::Emitter out;
    231             out << YAML::BeginMap;
    232             out << YAML::Key << s_AdminSettingsYaml_LocalManifestFiles << YAML::Value << m_settingValues.LocalManifestFiles;
    233             out << YAML::Key << s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore << YAML::Value << m_settingValues.BypassCertificatePinningForMicrosoftStore;
    234             out << YAML::Key << s_AdminSettingsYaml_InstallerHashOverride << YAML::Value << m_settingValues.InstallerHashOverride;
    235             out << YAML::Key << s_AdminSettingsYaml_LocalArchiveMalwareScanOverride << YAML::Value << m_settingValues.LocalArchiveMalwareScanOverride;
    236             out << YAML::Key << s_AdminSettingsYaml_ProxyCommandLineOptions << YAML::Value << m_settingValues.ProxyCommandLineOptions;
    237 
    238             if (m_settingValues.DefaultProxy)
    239             {
    240                 out << YAML::Key << s_AdminSettingsYaml_DefaultProxy << YAML::Value << m_settingValues.DefaultProxy.value();
    241             }
    242 
    243             out << YAML::EndMap;
    244 
    245             return m_settingStream.Set(out.str());
    246         }
    247 
    248         auto GetPolicyStateForSetting(BoolAdminSetting setting)
    249         {
    250             auto policy = GetAdminSettingPolicy(setting);
    251             return GroupPolicies().GetState(policy);
    252         }
    253 
    254         std::optional<std::reference_wrapper<const std::string>> GetPolicyStateForSetting(StringAdminSetting setting)
    255         {
    256             switch (setting)
    257             {
    258             case AppInstaller::Settings::StringAdminSetting::DefaultProxy:
    259                 return GroupPolicies().GetValueRef<ValuePolicy::DefaultProxy>();
    260             default:
    261                 return std::nullopt;
    262             }
    263         }
    264     }
    265 
    266     BoolAdminSetting StringToBoolAdminSetting(std::string_view in)
    267     {
    268         BoolAdminSetting result = BoolAdminSetting::Unknown;
    269 
    270         if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_LocalManifestFiles, in))
    271         {
    272             result = BoolAdminSetting::LocalManifestFiles;
    273         }
    274         else if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore, in))
    275         {
    276             result = BoolAdminSetting::BypassCertificatePinningForMicrosoftStore;
    277         }
    278         else if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_InstallerHashOverride, in))
    279         {
    280             result = BoolAdminSetting::InstallerHashOverride;
    281         }
    282         else if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_LocalArchiveMalwareScanOverride, in))
    283         {
    284             result = BoolAdminSetting::LocalArchiveMalwareScanOverride;
    285         }
    286         else if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_ProxyCommandLineOptions, in))
    287         {
    288             result = BoolAdminSetting::ProxyCommandLineOptions;
    289         }
    290 
    291         return result;
    292     }
    293 
    294     StringAdminSetting StringToStringAdminSetting(std::string_view in)
    295     {
    296         StringAdminSetting result = StringAdminSetting::Unknown;
    297 
    298         if (Utility::CaseInsensitiveEquals(s_AdminSettingsYaml_DefaultProxy, in))
    299         {
    300             result = StringAdminSetting::DefaultProxy;
    301         }
    302 
    303         return result;
    304     }
    305 
    306     Utility::LocIndView AdminSettingToString(BoolAdminSetting setting)
    307     {
    308         switch (setting)
    309         {
    310         case BoolAdminSetting::LocalManifestFiles:
    311             return s_AdminSettingsYaml_LocalManifestFiles;
    312         case BoolAdminSetting::BypassCertificatePinningForMicrosoftStore:
    313             return s_AdminSettingsYaml_BypassCertificatePinningForMicrosoftStore;
    314         case BoolAdminSetting::InstallerHashOverride:
    315             return s_AdminSettingsYaml_InstallerHashOverride;
    316         case BoolAdminSetting::LocalArchiveMalwareScanOverride:
    317             return s_AdminSettingsYaml_LocalArchiveMalwareScanOverride;
    318         case BoolAdminSetting::ProxyCommandLineOptions:
    319             return s_AdminSettingsYaml_ProxyCommandLineOptions;
    320         default:
    321             return "Unknown"_liv;
    322         }
    323     }
    324 
    325     Utility::LocIndView AdminSettingToString(StringAdminSetting setting)
    326     {
    327         switch (setting)
    328         {
    329         case StringAdminSetting::DefaultProxy:
    330             return s_AdminSettingsYaml_DefaultProxy;
    331         default:
    332             return "Unknown"_liv;
    333         }
    334     }
    335 
    336     TogglePolicy::Policy GetAdminSettingPolicy(BoolAdminSetting setting)
    337     {
    338         switch (setting)
    339         {
    340         case BoolAdminSetting::LocalManifestFiles:
    341             return TogglePolicy::Policy::LocalManifestFiles;
    342         case BoolAdminSetting::BypassCertificatePinningForMicrosoftStore:
    343             return TogglePolicy::Policy::BypassCertificatePinningForMicrosoftStore;
    344         case BoolAdminSetting::InstallerHashOverride:
    345             return TogglePolicy::Policy::HashOverride;
    346         case BoolAdminSetting::LocalArchiveMalwareScanOverride:
    347             return TogglePolicy::Policy::LocalArchiveMalwareScanOverride;
    348         case BoolAdminSetting::ProxyCommandLineOptions:
    349             return TogglePolicy::Policy::ProxyCommandLineOptions;
    350         default:
    351             return TogglePolicy::Policy::None;
    352         }
    353     }
    354 
    355     bool EnableAdminSetting(BoolAdminSetting setting)
    356     {
    357         if (GetPolicyStateForSetting(setting) == PolicyState::Disabled)
    358         {
    359             return false;
    360         }
    361 
    362         AdminSettingsInternal adminSettingsInternal;
    363         adminSettingsInternal.SetAdminSetting(setting, true);
    364         return true;
    365     }
    366 
    367     bool DisableAdminSetting(BoolAdminSetting setting)
    368     {
    369         if (GetPolicyStateForSetting(setting) == PolicyState::Enabled)
    370         {
    371             return false;
    372         }
    373 
    374         AdminSettingsInternal adminSettingsInternal;
    375         adminSettingsInternal.SetAdminSetting(setting, false);
    376         return true;
    377     }
    378 
    379     bool IsAdminSettingEnabled(BoolAdminSetting setting)
    380     {
    381         // Check for a policy that overrides this setting.
    382         auto policyState = GetPolicyStateForSetting(setting);
    383         if (policyState != PolicyState::NotConfigured)
    384         {
    385             return policyState == PolicyState::Enabled;
    386         }
    387 
    388         AdminSettingsInternal adminSettingsInternal;
    389         return adminSettingsInternal.GetAdminSettingValue(setting);
    390     }
    391 
    392     bool SetAdminSetting(StringAdminSetting setting, std::string_view value)
    393     {
    394         if (GetPolicyStateForSetting(setting))
    395         {
    396             return false;
    397         }
    398 
    399         AdminSettingsInternal adminSettingsInternal;
    400         adminSettingsInternal.SetAdminSetting(setting, std::string{ value });
    401         return true;
    402     }
    403 
    404     bool ResetAdminSetting(StringAdminSetting setting)
    405     {
    406         if (GetPolicyStateForSetting(setting))
    407         {
    408             return false;
    409         }
    410 
    411         AdminSettingsInternal adminSettingsInternal;
    412         adminSettingsInternal.SetAdminSetting(setting, std::nullopt);
    413         return true;
    414     }
    415 
    416     void ResetAllAdminSettings()
    417     {
    418         AdminSettingsInternal{}.Reset();
    419     }
    420 
    421     std::optional<std::string> GetAdminSetting(StringAdminSetting setting)
    422     {
    423         // Check for a policy that overrides this setting.
    424         auto policyState = GetPolicyStateForSetting(setting);
    425         if (policyState)
    426         {
    427             return policyState.value();
    428         }
    429 
    430         AdminSettingsInternal adminSettingsInternal;
    431         return adminSettingsInternal.GetAdminSettingValue(setting);
    432     }
    433 
    434     std::vector<BoolAdminSetting> GetAllBoolAdminSettings()
    435     {
    436         return GetAllSequentialEnumValues(BoolAdminSetting::Unknown);
    437     }
    438 
    439     std::vector<StringAdminSetting> GetAllStringAdminSettings()
    440     {
    441         return GetAllSequentialEnumValues(StringAdminSetting::Unknown);
    442     }
    443 
    444 }