ConfigurationStaticFunctions.cpp (14552B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License 3 #include <Unknwn.h> 4 #include <wil\cppwinrt_wrl.h> 5 #include <winrt/Microsoft.Management.Configuration.h> 6 #include <winrt/Microsoft.Management.Deployment.h> 7 #include <ComClsids.h> 8 #include <AppInstallerErrors.h> 9 #include <AppInstallerFileLogger.h> 10 #include <AppInstallerLanguageUtilities.h> 11 #include <AppInstallerStrings.h> 12 #include <winget/ConfigurationSetProcessorHandlers.h> 13 #include <ConfigurationSetProcessorFactoryRemoting.h> 14 #include <ShutdownMonitoring.h> 15 #include <winget/ILifetimeWatcher.h> 16 #include <winget/IConfigurationStaticsInternals.h> 17 #include <winget/GroupPolicy.h> 18 #include <winget/Security.h> 19 #include <winget/ThreadGlobals.h> 20 #include <winget/SelfManagement.h> 21 #include <winget/MSStore.h> 22 #include <winget/ExperimentalFeature.h> 23 24 using namespace AppInstaller::SelfManagement; 25 using namespace winrt::Microsoft::Management::Deployment; 26 using namespace winrt::Windows::Foundation::Collections; 27 28 namespace ConfigurationShim 29 { 30 namespace 31 { 32 static std::atomic_bool s_canBeCreated{ true }; 33 34 auto GetInternalStatics() 35 { 36 return winrt::Microsoft::Management::Configuration::ConfigurationStaticFunctions().as<AppInstaller::WinRT::IConfigurationStaticsInternals>(); 37 } 38 39 void BlockNewWorkForShutdown(AppInstaller::CancelReason) 40 { 41 GetInternalStatics()->BlockNewWorkForShutdown(); 42 } 43 44 void BeginShutdown(AppInstaller::CancelReason) 45 { 46 GetInternalStatics()->BeginShutdown(); 47 } 48 49 void WaitForShutdown() 50 { 51 GetInternalStatics()->WaitForShutdown(); 52 } 53 54 void RegisterForShutdownSynchronization() 55 { 56 static std::once_flag registerComponentOnceFlag; 57 std::call_once(registerComponentOnceFlag, 58 [&]() 59 { 60 using namespace AppInstaller::ShutdownMonitoring; 61 62 ServerShutdownSynchronization::ComponentSystem component; 63 component.BlockNewWork = BlockNewWorkForShutdown; 64 component.BeginShutdown = BeginShutdown; 65 component.Wait = WaitForShutdown; 66 67 ServerShutdownSynchronization::AddComponent(component); 68 }); 69 } 70 } 71 72 CLSID CLSID_ConfigurationObjectLifetimeWatcher = { 0x89a8f1d4,0x1e24,0x46a4,{0x9f,0x6c,0x65,0x78,0xb0,0x47,0xf2,0xf7} }; 73 74 struct 75 DECLSPEC_UUID("89a8f1d4-1e24-46a4-9f6c-6578b047f2f7") 76 ConfigurationObjectLifetimeWatcher : winrt::implements<ConfigurationObjectLifetimeWatcher, IUnknown> 77 { 78 }; 79 80 struct 81 DECLSPEC_UUID(WINGET_OUTOFPROC_COM_CLSID_ConfigurationStaticFunctions) 82 ConfigurationStaticFunctionsShim : winrt::implements<ConfigurationStaticFunctionsShim, 83 winrt::Microsoft::Management::Configuration::IConfigurationStatics, 84 winrt::Microsoft::Management::Configuration::IConfigurationStatics2, 85 winrt::Microsoft::Management::Configuration::IConfigurationStatics3> 86 { 87 ConfigurationStaticFunctionsShim() 88 { 89 auto threadGlobalsRestore = m_threadGlobals.SetForCurrentThread(); 90 auto& diagnosticsLogger = m_threadGlobals.GetDiagnosticLogger(); 91 diagnosticsLogger.SetEnabledChannels(AppInstaller::Logging::Channel::All); 92 diagnosticsLogger.SetLevel(AppInstaller::Logging::Level::Verbose); 93 diagnosticsLogger.AddLogger(std::make_unique<AppInstaller::Logging::FileLogger>("WinGetCFG"sv)); 94 95 if (IsConfigurationAvailable()) 96 { 97 m_statics = winrt::Microsoft::Management::Configuration::ConfigurationStaticFunctions().as<winrt::Microsoft::Management::Configuration::IConfigurationStatics3>(); 98 RegisterForShutdownSynchronization(); 99 } 100 } 101 102 winrt::Microsoft::Management::Configuration::ConfigurationUnit CreateConfigurationUnit() 103 { 104 THROW_HR_IF(CO_E_CLASS_DISABLED, !s_canBeCreated); 105 106 if (!m_statics) 107 { 108 THROW_HR(APPINSTALLER_CLI_ERROR_PACKAGE_IS_STUB); 109 } 110 111 auto result = m_statics.CreateConfigurationUnit(); 112 result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); 113 return result; 114 } 115 116 winrt::Microsoft::Management::Configuration::ConfigurationSet CreateConfigurationSet() 117 { 118 THROW_HR_IF(CO_E_CLASS_DISABLED, !s_canBeCreated); 119 120 if (!m_statics) 121 { 122 THROW_HR(APPINSTALLER_CLI_ERROR_PACKAGE_IS_STUB); 123 } 124 125 auto result = m_statics.CreateConfigurationSet(); 126 result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); 127 return result; 128 } 129 130 winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory> CreateConfigurationSetProcessorFactoryAsync(winrt::hstring const& handler) 131 { 132 THROW_HR_IF(CO_E_CLASS_DISABLED, !s_canBeCreated); 133 134 auto strong_this{ get_strong() }; 135 std::wstring lowerHandler = AppInstaller::Utility::ToLower(handler); 136 137 co_await winrt::resume_background(); 138 139 auto threadGlobalsRestore = m_threadGlobals.SetForCurrentThread(); 140 winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory result; 141 142 if (lowerHandler == AppInstaller::Configuration::PowerShellHandlerIdentifier) 143 { 144 result = AppInstaller::CLI::ConfigurationRemoting::CreateOutOfProcessFactory(AppInstaller::CLI::ConfigurationRemoting::ProcessorEngine::PowerShell); 145 } 146 else if (lowerHandler == AppInstaller::Configuration::DynamicRuntimeHandlerIdentifier) 147 { 148 result = AppInstaller::CLI::ConfigurationRemoting::CreateDynamicRuntimeFactory(AppInstaller::CLI::ConfigurationRemoting::ProcessorEngine::PowerShell); 149 } 150 else if (lowerHandler == AppInstaller::Configuration::DSCv3HandlerIdentifier) 151 { 152 result = AppInstaller::CLI::ConfigurationRemoting::CreateOutOfProcessFactory(AppInstaller::CLI::ConfigurationRemoting::ProcessorEngine::DSCv3); 153 } 154 else if (lowerHandler == AppInstaller::Configuration::DSCv3DynamicRuntimeHandlerIdentifier) 155 { 156 result = AppInstaller::CLI::ConfigurationRemoting::CreateDynamicRuntimeFactory(AppInstaller::CLI::ConfigurationRemoting::ProcessorEngine::DSCv3); 157 } 158 159 if (result) 160 { 161 // Objects returned here *must* implement ILifetimeWatcher for now. 162 // If we create OOP objects implemented elsewhere in the future, decide then how to exempt those while still ensuring we 163 // don't accidentally create a lifetime bug by basing it solely off the QI result. 164 result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); 165 co_return result; 166 } 167 168 AICLI_LOG(Config, Error, << "Unknown handler in CreateConfigurationSetProcessorFactory: " << AppInstaller::Utility::ConvertToUTF8(handler)); 169 THROW_HR(E_NOT_SET); 170 } 171 172 winrt::Microsoft::Management::Configuration::ConfigurationProcessor CreateConfigurationProcessor(winrt::Microsoft::Management::Configuration::IConfigurationSetProcessorFactory const& factory) 173 { 174 THROW_HR_IF(CO_E_CLASS_DISABLED, !s_canBeCreated); 175 176 if (!m_statics) 177 { 178 THROW_HR(APPINSTALLER_CLI_ERROR_PACKAGE_IS_STUB); 179 } 180 181 auto result = m_statics.CreateConfigurationProcessor(factory); 182 result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); 183 return result; 184 } 185 186 bool IsConfigurationAvailable() 187 { 188 return !IsStubPackage(); 189 } 190 191 winrt::Windows::Foundation::IAsyncActionWithProgress<uint32_t> EnsureConfigurationAvailableAsync() 192 { 193 THROW_HR_IF(CO_E_CLASS_DISABLED, !s_canBeCreated); 194 195 if (IsConfigurationAvailable()) 196 { 197 return; 198 } 199 200 auto strong_this{ get_strong() }; 201 co_await winrt::resume_background(); 202 203 SetStubPreferred(false); 204 205 PackageManager packageManager; 206 PackageCatalogReference catalogRef{ packageManager.GetPredefinedPackageCatalog(PredefinedPackageCatalog::MicrosoftStore) }; 207 THROW_HR_IF(APPINSTALLER_CLI_ERROR_INTERNAL_ERROR, !catalogRef); 208 209 ConnectResult connectResult = catalogRef.Connect(); 210 THROW_HR_IF(APPINSTALLER_CLI_ERROR_SOURCE_OPEN_FAILED, connectResult.Status() != ConnectResultStatus::Ok); 211 212 PackageCatalog catalog = connectResult.PackageCatalog(); 213 214 FindPackagesOptions findPackagesOptions; 215 PackageMatchFilter filter; 216 filter.Field(PackageMatchField::Id); 217 filter.Option(PackageFieldMatchOption::Equals); 218 filter.Value(AppInstaller::MSStore::s_AppInstallerProductId); 219 findPackagesOptions.Filters().Append(filter); 220 221 FindPackagesResult findPackagesResult{ catalog.FindPackages(findPackagesOptions) }; 222 223 auto matches = findPackagesResult.Matches(); 224 THROW_HR_IF(APPINSTALLER_CLI_ERROR_MISSING_PACKAGE, matches.Size() == 0); 225 auto catalogPackage = matches.GetAt(0).CatalogPackage(); 226 227 InstallOptions installOptions; 228 installOptions.AcceptPackageAgreements(true); 229 installOptions.AllowUpgradeToUnknownVersion(true); 230 installOptions.Force(true); 231 232 auto progress = co_await winrt::get_progress_token(); 233 234 // Don't use UpgradePackageAsync, we don't support upgrade for packages from the msstore 235 // it has to be install and internally we know is an update. 236 auto installTask = packageManager.InstallPackageAsync(catalogPackage, installOptions); 237 installTask.Progress([progress](auto const&, InstallProgress installProgress) 238 { 239 if (installProgress.State == PackageInstallProgressState::Downloading && installProgress.BytesRequired != 0) 240 { 241 progress((uint32_t)(installProgress.DownloadProgress * 80)); 242 } 243 else if (installProgress.State == PackageInstallProgressState::Installing) 244 { 245 progress(((uint32_t)installProgress.InstallationProgress * 20) + 80); 246 } 247 }); 248 249 co_await installTask; 250 s_canBeCreated = false; 251 } 252 253 winrt::Microsoft::Management::Configuration::ConfigurationParameter CreateConfigurationParameter() 254 { 255 THROW_HR_IF(CO_E_CLASS_DISABLED, !s_canBeCreated); 256 257 if (!m_statics) 258 { 259 THROW_HR(APPINSTALLER_CLI_ERROR_PACKAGE_IS_STUB); 260 } 261 262 auto result = m_statics.CreateConfigurationParameter(); 263 result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); 264 return result; 265 } 266 267 winrt::Microsoft::Management::Configuration::FindUnitProcessorsOptions CreateFindUnitProcessorsOptions() 268 { 269 THROW_HR_IF(CO_E_CLASS_DISABLED, !s_canBeCreated); 270 271 if (!m_statics) 272 { 273 THROW_HR(APPINSTALLER_CLI_ERROR_PACKAGE_IS_STUB); 274 } 275 276 auto result = m_statics.CreateFindUnitProcessorsOptions(); 277 result.as<AppInstaller::WinRT::ILifetimeWatcher>()->SetLifetimeWatcher(CreateLifetimeWatcher()); 278 return result; 279 } 280 281 private: 282 // Returns a lifetime watcher object that is currently *unowned*. 283 IUnknown* CreateLifetimeWatcher() 284 { 285 ::Microsoft::WRL::ComPtr<IClassFactory> factory; 286 THROW_IF_FAILED(::Microsoft::WRL::Module<::Microsoft::WRL::ModuleType::OutOfProc>::GetModule().GetClassObject(CLSID_ConfigurationObjectLifetimeWatcher, IID_PPV_ARGS(&factory))); 287 winrt::com_ptr<IUnknown> out; 288 THROW_IF_FAILED(factory->CreateInstance(nullptr, __uuidof(IUnknown), out.put_void())); 289 return out.detach(); 290 } 291 292 winrt::Microsoft::Management::Configuration::IConfigurationStatics3 m_statics = nullptr; 293 AppInstaller::ThreadLocalStorage::WingetThreadGlobals m_threadGlobals; 294 }; 295 296 // Enable custom code to run before creating any object through the factory. 297 template <typename TCppWinRTClass> 298 class ConfigurationFactory : public ::wil::wrl_factory_for_winrt_com_class<TCppWinRTClass> 299 { 300 public: 301 IFACEMETHODIMP CreateInstance(_In_opt_::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void** object) noexcept try 302 { 303 *object = nullptr; 304 RETURN_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::WinGet)); 305 RETURN_HR_IF(APPINSTALLER_CLI_ERROR_BLOCKED_BY_POLICY, !::AppInstaller::Settings::GroupPolicies().IsEnabled(::AppInstaller::Settings::TogglePolicy::Policy::Configuration)); 306 RETURN_HR_IF(E_ACCESSDENIED, !::AppInstaller::Security::IsCOMCallerSameUserAndIntegrityLevel()); 307 308 RETURN_HR_IF(CO_E_CLASS_DISABLED, !s_canBeCreated); 309 310 return ::wil::wrl_factory_for_winrt_com_class<TCppWinRTClass>::CreateInstance(unknownOuter, riid, object); 311 } 312 CATCH_RETURN() 313 }; 314 315 #define CoCreatableMicrosoftManagementConfigurationClass(className) \ 316 CoCreatableClassWithFactory(className, ::ConfigurationShim::ConfigurationFactory<className>) 317 318 // Disable 6388 as it seems to be falsely warning 319 #pragma warning(push) 320 #pragma warning(disable : 6388) 321 CoCreatableCppWinRtClass(ConfigurationObjectLifetimeWatcher); 322 CoCreatableMicrosoftManagementConfigurationClass(ConfigurationStaticFunctionsShim); 323 #pragma warning(pop) 324 }