// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/device_signals/core/system_signals/win/wsc_client_impl.h"
#include <windows.h>
#include <iwscapi.h>
#include <wrl/client.h>
#include <wscapi.h>
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/win/com_init_util.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_variant.h"
#include "base/win/windows_version.h"
using Microsoft::WRL::ComPtr;
namespace device_signals {
namespace {
AvProductState ConvertState(WSC_SECURITY_PRODUCT_STATE state) {
switch (state) {
case WSC_SECURITY_PRODUCT_STATE_ON:
return AvProductState::kOn;
case WSC_SECURITY_PRODUCT_STATE_OFF:
return AvProductState::kOff;
case WSC_SECURITY_PRODUCT_STATE_SNOOZED:
return AvProductState::kSnoozed;
case WSC_SECURITY_PRODUCT_STATE_EXPIRED:
return AvProductState::kExpired;
}
}
HRESULT CreateProductList(ComPtr<IWSCProductList>* out_product_list) {
ComPtr<IWSCProductList> product_list;
HRESULT hr =
::CoCreateInstance(__uuidof(WSCProductList), nullptr,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&product_list));
if (!FAILED(hr)) {
*out_product_list = product_list;
}
return hr;
}
} // namespace
WscClientImpl::WscClientImpl()
: create_callback_(base::BindRepeating(CreateProductList)) {}
WscClientImpl::WscClientImpl(CreateProductListCallback create_callback)
: create_callback_(std::move(create_callback)) {}
WscClientImpl::~WscClientImpl() = default;
WscAvProductsResponse WscClientImpl::GetAntiVirusProducts() {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
base::BlockingType::MAY_BLOCK);
WscAvProductsResponse response;
ComPtr<IWSCProductList> product_list;
HRESULT hr = create_callback_.Run(&product_list);
if (FAILED(hr)) {
response.query_error = WscQueryError::kFailedToCreateInstance;
return response;
}
hr = product_list->Initialize(WSC_SECURITY_PROVIDER_ANTIVIRUS);
if (FAILED(hr)) {
response.query_error = WscQueryError::kFailedToInitializeProductList;
return response;
}
LONG product_count;
hr = product_list->get_Count(&product_count);
if (FAILED(hr)) {
response.query_error = WscQueryError::kFailedToGetProductCount;
return response;
}
for (LONG i = 0; i < product_count; i++) {
ComPtr<IWscProduct> product;
hr = product_list->get_Item(i, &product);
if (FAILED(hr)) {
response.parsing_errors.push_back(WscParsingError::kFailedToGetItem);
continue;
}
AvProduct av_product;
WSC_SECURITY_PRODUCT_STATE product_state;
hr = product->get_ProductState(&product_state);
if (FAILED(hr)) {
response.parsing_errors.push_back(WscParsingError::kFailedToGetState);
continue;
}
av_product.state = ConvertState(product_state);
base::win::ScopedBstr product_name;
hr = product->get_ProductName(product_name.Receive());
if (FAILED(hr)) {
response.parsing_errors.push_back(WscParsingError::kFailedToGetName);
continue;
}
av_product.display_name = base::SysWideToUTF8(
std::wstring(product_name.Get(), product_name.Length()));
base::win::ScopedBstr product_id;
hr = product->get_ProductGuid(product_id.Receive());
if (FAILED(hr)) {
response.parsing_errors.push_back(WscParsingError::kFailedToGetId);
continue;
}
av_product.product_id = base::SysWideToUTF8(
std::wstring(product_id.Get(), product_id.Length()));
response.av_products.push_back(std::move(av_product));
}
return response;
}
} // namespace device_signals