You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
dp4-uos/example/service/policy.cpp

542 lines
18 KiB

// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "policy.h"
#include <QDebug>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLoggingCategory>
Q_LOGGING_CATEGORY(dsm_policy, "[Policy]")
Policy::Policy(QObject *parent)
: QObject(parent)
{
}
bool Policy::checkPathHide(const QString &path)
{
QMapPathHide::iterator iter = mapPathHide.find(path);
if (iter == mapPathHide.end()) {
return false;
}
return iter.value();
}
bool Policy::checkMethodPermission(const QString &process,
const QString &path,
const QString &interface,
const QString &method)
{
return checkPermission(process, path, interface, method, CallDestType::Method);
}
bool Policy::checkPropertyPermission(const QString &process,
const QString &path,
const QString &interface,
const QString &property)
{
return checkPermission(process, path, interface, property, CallDestType::Property);
}
bool Policy::checkPermission(const QString &process,
const QString &path,
const QString &interface,
const QString &dest,
const CallDestType &type)
{
qCInfo(dsm_policy) << "check permission:"
<< QString("process=%1, path=%2, interface=%3, dest=%4")
.arg(process, path, interface, dest);
// 时间复杂度跟权限配置复杂度正相关,简单的配置就会校验很快
QMapPath::const_iterator iterPath = mapPath.find(path);
if (iterPath == mapPath.end()) {
// 默认不校验,即有权限
return true;
}
// PATH权限
const PolicyPath &policyPath = iterPath.value();
QMapInterface::const_iterator iterInterface = policyPath.interfaces.find(interface);
if (iterInterface == policyPath.interfaces.end()) {
// 没有配置interface权限,则用path权限
if (!policyPath.needPermission) {
return true;
}
return policyPath.processes.contains(process);
}
if (type == CallDestType::Method) {
// INTERFACE权限
const PolicyInterface &policyInterface = iterInterface.value();
QMapMethod::const_iterator iterMethod = policyInterface.methods.find(dest);
if (iterMethod == policyInterface.methods.end()) {
if (!policyInterface.needPermission) {
return true;
}
return policyInterface.processes.contains(process);
}
// METHOD权限
const PolicyMethod &policyMethod = iterMethod.value();
if (!policyMethod.needPermission) {
return true;
}
return policyMethod.processes.contains(process);
} else if (type == CallDestType::Property) {
// INTERFACE权限
const PolicyInterface &policyInterface = iterInterface.value();
QMapProperty::const_iterator iterProp = policyInterface.properties.find(dest);
if (iterProp == policyInterface.properties.end()) {
if (!policyInterface.needPermission) {
return true;
}
return policyInterface.processes.contains(process);
}
// PROPERTY权限
const PolicyProperty &policyProp = iterProp.value();
if (!policyProp.needPermission) {
return true;
}
return policyProp.processes.contains(process);
}
qCWarning(dsm_policy) << "check permission error!";
return false;
}
QStringList Policy::paths() const
{
return mapSubPath.keys();
}
bool Policy::allowSubPath(const QString &path) const
{
auto iter = mapSubPath.find(path);
if (iter != mapSubPath.end()) {
return iter.value();
}
return false;
}
bool Policy::isResident() const
{
return startType == "Resident";
}
void Policy::print()
{
qInfo() << "-------------------------------------";
qInfo() << "DBUS POLICY CONFIG";
qInfo() << "- name:" << name;
qInfo() << "- path hide";
for (QMapPathHide::iterator iter = mapPathHide.begin(); iter != mapPathHide.end(); iter++) {
qInfo() << "-- path hide:" << iter.key() << iter.value();
}
qInfo() << "- whitelist";
for (QMapWhitelists::iterator iter = mapWhitelist.begin(); iter != mapWhitelist.end(); iter++) {
qInfo() << "-- whitelist:" << iter.key() << iter.value().name << iter.value().process;
}
qInfo() << "- policy";
for (QMapPath::iterator iter = mapPath.begin(); iter != mapPath.end(); iter++) {
qInfo() << "-- path:" << iter.key() << iter.value().path;
qInfo() << "-- permission:" << iter.value().needPermission;
qInfo() << "-- whitelist:" << iter.value().processes;
for (QMapInterface::iterator iterInterface = iter.value().interfaces.begin();
iterInterface != iter.value().interfaces.end();
iterInterface++) {
qInfo() << "---- interface:" << iterInterface.key() << iterInterface.value().interface;
qInfo() << "---- permission:" << iterInterface.value().needPermission;
qInfo() << "---- whitelist:" << iterInterface.value().processes;
for (QMapMethod::iterator iterMethod = iterInterface.value().methods.begin();
iterMethod != iterInterface.value().methods.end();
iterMethod++) {
qInfo() << "------ method:" << iterMethod.key() << iterMethod.value().method;
qInfo() << "------ permission:" << iterMethod.value().needPermission;
qInfo() << "------ whitelist:" << iterMethod.value().processes;
}
for (QMapProperty::iterator iterProp = iterInterface.value().properties.begin();
iterProp != iterInterface.value().properties.end();
iterProp++) {
qInfo() << "------ property:" << iterProp.key() << iterProp.value().property;
qInfo() << "------ permission:" << iterProp.value().needPermission;
qInfo() << "------ whitelist:" << iterProp.value().processes;
}
}
}
qInfo() << "-------------------------------------";
}
void Policy::parseConfig(const QString &path)
{
qCInfo(dsm_policy) << "parse config:" << path;
if (path.isEmpty()) {
qCWarning(dsm_policy) << "path is empty!";
return;
}
QJsonDocument jsonDoc;
if (!readJsonFile(jsonDoc, path)) {
qCWarning(dsm_policy) << "read json file failed!";
return;
}
QJsonObject rootObj = jsonDoc.object();
jsonGetString(rootObj, "name", name);
jsonGetString(rootObj, "group", group, "app");
jsonGetString(rootObj, "libPath", pluginPath); // 兼容
jsonGetString(rootObj, "pluginPath", pluginPath, pluginPath);
jsonGetString(rootObj, "policyVersion", version, "1.0"); // 兼容
jsonGetString(rootObj, "version", version, version);
jsonGetString(rootObj, "policyStartType", startType, "Resident"); // 兼容
jsonGetString(rootObj, "startType", startType, startType);
jsonGetStringList(rootObj, "dependencies", dependencies);
jsonGetInt(rootObj, "startDelay", startDelay, 0);
jsonGetInt(rootObj, "idleTime", idleTime, 10);
// get SDKType
QString sdkTypeString;
jsonGetString(rootObj, "pluginType", sdkTypeString, "qt");
if (sdkTypeString == "qt")
sdkType = SDKType::QT;
if (sdkTypeString == "sd")
sdkType = SDKType::SD;
if (name.isEmpty()) {
qCWarning(dsm_policy) << "json error, name is empty.";
return;
}
if (!parseWhitelist(rootObj)) {
qCWarning(dsm_policy) << "json error, parse whitelist error.";
return;
}
if (!parsePolicy(rootObj)) {
qCWarning(dsm_policy) << "json error, parse policy error.";
return;
}
}
bool Policy::readJsonFile(QJsonDocument &outDoc, const QString &fileName)
{
QFile jsonFIle(fileName);
if (!jsonFIle.open(QIODevice::ReadOnly)) {
qCWarning(dsm_policy) << QString("open file: %1 error!").arg(fileName);
return false;
}
QJsonParseError jsonParserError;
outDoc = QJsonDocument::fromJson(jsonFIle.readAll(), &jsonParserError);
jsonFIle.close();
if (jsonParserError.error != QJsonParseError::NoError) {
qCWarning(dsm_policy) << "to json document error: " << jsonParserError.errorString();
return false;
}
if (outDoc.isNull()) {
qCWarning(dsm_policy) << "json document is null!";
return false;
}
return true;
}
// typedef QMap<QString, PolicyWhitelist> QMapWhitelists;
bool Policy::parseWhitelist(const QJsonObject &obj)
{
mapWhitelist.clear();
if (!obj.contains("whitelists")) {
// 为空,不是出错
return true;
}
QJsonValue listsValue = obj.value("whitelists");
if (!listsValue.isArray()) {
qCWarning(dsm_policy) << "parse whitelist error, must be json array!";
return false;
}
QJsonArray lists = listsValue.toArray();
for (int i = 0; i < lists.size(); ++i) {
QJsonValue whitelistValue = lists.at(i);
if (whitelistValue.isObject()) {
PolicyWhitelist whitelist;
QJsonObject whitelistObj = whitelistValue.toObject();
QString name;
jsonGetString(whitelistObj, "name", name);
if (name.isEmpty()) {
continue;
}
if (!whitelistObj.contains("process")) {
continue;
}
QJsonArray processes = whitelistObj.value("process").toArray();
if (processes.size() <= 0) {
continue;
}
whitelist.name = name;
for (int j = 0; j < processes.size(); ++j) {
if (processes.at(j).isString()) {
whitelist.process.append(processes.at(j).toString());
}
}
mapWhitelist.insert(name, whitelist);
}
}
return true;
}
bool Policy::parsePolicy(const QJsonObject &obj)
{
mapPathHide.clear();
mapPath.clear();
if (!obj.contains("policy")) {
// 为空,不是出错
return true;
}
QJsonValue policyValue = obj.value("policy");
if (!policyValue.isArray()) {
qCWarning(dsm_policy) << "parse policy error, must be json array!";
return false;
}
QJsonArray policyList = policyValue.toArray();
for (int i = 0; i < policyList.size(); ++i) {
QJsonValue policy = policyList.at(i);
if (!policy.isObject())
continue;
if (!parsePolicyPath(policy.toObject())) {
return false;
}
}
return true;
}
bool Policy::parsePolicyPath(const QJsonObject &obj)
{
QString path;
jsonGetString(obj, "path", path);
if (path.isEmpty()) {
qCWarning(dsm_policy) << "parse policy-path error, must be a string!";
return false;
}
bool pathHide;
jsonGetBool(obj, "pathhide", pathHide, false);
mapPathHide.insert(path, pathHide);
bool subpath;
jsonGetBool(obj, "subpath", subpath, false);
mapSubPath.insert(path, pathHide);
PolicyPath policyPath;
policyPath.path = path;
jsonGetBool(obj, "permission", policyPath.needPermission, false);
QString whitelist;
jsonGetString(obj, "whitelist", whitelist);
if (!whitelist.isEmpty()) {
QMapWhitelists::const_iterator iterWhitelist = mapWhitelist.find(whitelist);
if (iterWhitelist != mapWhitelist.end() && iterWhitelist.value().name == whitelist) {
policyPath.processes = iterWhitelist.value().process;
}
}
if (obj.contains("interfaces")) {
QJsonValue interfaces = obj.value("interfaces");
if (interfaces.isArray()) {
QJsonArray interfaceList = interfaces.toArray();
for (int i = 0; i < interfaceList.size(); ++i) {
QJsonValue interface = interfaceList.at(i);
if (interface.isObject()) {
bool ret = parsePolicyInterface(interface.toObject(), policyPath);
if (!ret) {
return false;
}
}
}
}
}
mapPath.insert(path, policyPath);
return true;
}
bool Policy::parsePolicyInterface(const QJsonObject &obj, PolicyPath &policyPath)
{
QString interface;
jsonGetString(obj, "interface", interface);
if (interface.isEmpty()) {
qCWarning(dsm_policy) << "parse policy-interface error, must be a string!";
return false;
}
PolicyInterface policyInterface;
policyInterface.interface = interface;
// interface没有指定permission,则使用上级path的permission
jsonGetBool(obj, "permission", policyInterface.needPermission, policyPath.needPermission);
QString whitelist;
jsonGetString(obj, "whitelist", whitelist);
if (!whitelist.isEmpty()) {
QMapWhitelists::const_iterator iterWhitelist = mapWhitelist.find(whitelist);
if (iterWhitelist != mapWhitelist.end() && iterWhitelist.value().name == whitelist) {
policyInterface.processes = iterWhitelist.value().process;
} // esle 错误的whitelist认为是空值
} else {
// interface没有指定whitelist,则使用上级path的whitelist
policyInterface.processes = policyPath.processes;
}
if (obj.contains("methods")) {
QJsonValue methods = obj.value("methods");
if (methods.isArray()) {
QJsonArray methodList = methods.toArray();
for (int i = 0; i < methodList.size(); ++i) {
QJsonValue method = methodList.at(i);
if (method.isObject()) {
bool ret = parsePolicyMethod(method.toObject(), policyInterface);
if (!ret) {
return false;
}
}
}
}
}
if (obj.contains("properties")) {
QJsonValue properties = obj.value("properties");
if (properties.isArray()) {
QJsonArray propertiesList = properties.toArray();
for (int i = 0; i < propertiesList.size(); ++i) {
QJsonValue property = propertiesList.at(i);
if (property.isObject()) {
bool ret = parsePolicyProperties(property.toObject(), policyInterface);
if (!ret) {
return false;
}
}
}
}
}
policyPath.interfaces.insert(interface, policyInterface);
return true;
}
bool Policy::parsePolicyMethod(const QJsonObject &obj, PolicyInterface &policyInterface)
{
QString method;
jsonGetString(obj, "method", method);
if (method.isEmpty()) {
qCWarning(dsm_policy) << "parse policy-method error, must be a string!";
return false;
}
PolicyMethod policyMethod;
policyMethod.method = method;
// method没有指定permission,则使用上级interface的permission
jsonGetBool(obj, "permission", policyMethod.needPermission, policyInterface.needPermission);
QString whitelist;
jsonGetString(obj, "whitelist", whitelist);
if (!whitelist.isEmpty()) {
QMapWhitelists::const_iterator iterWhitelist = mapWhitelist.find(whitelist);
if (iterWhitelist != mapWhitelist.end() && iterWhitelist.value().name == whitelist) {
policyMethod.processes = iterWhitelist.value().process;
}
} else {
// method没有指定whitelist,则使用上级interface的whitelist
policyMethod.processes = policyInterface.processes;
}
policyInterface.methods.insert(method, policyMethod);
return true;
}
bool Policy::parsePolicyProperties(const QJsonObject &obj, PolicyInterface &policyInterface)
{
QString property;
jsonGetString(obj, "property", property);
if (property.isEmpty()) {
qCWarning(dsm_policy) << "parse policy-property error, must be a string!";
return false;
}
PolicyProperty policyproperty;
policyproperty.property = property;
jsonGetBool(obj, "permission", policyproperty.needPermission, policyInterface.needPermission);
QString whitelist;
jsonGetString(obj, "whitelist", whitelist);
if (!whitelist.isEmpty()) {
QMapWhitelists::const_iterator iterWhitelist = mapWhitelist.find(whitelist);
if (iterWhitelist != mapWhitelist.end() && iterWhitelist.value().name == whitelist) {
policyproperty.processes = iterWhitelist.value().process;
}
} else {
policyproperty.processes = policyInterface.processes;
}
policyInterface.properties.insert(property, policyproperty);
return true;
}
bool Policy::jsonGetString(const QJsonObject &obj,
const QString &key,
QString &value,
QString defaultValue)
{
if (obj.contains(key)) {
const QJsonValue &v = obj.value(key);
if (v.isString()) {
value = v.toString();
return true;
}
}
value = defaultValue;
return false;
}
bool Policy::jsonGetStringList(const QJsonObject &obj,
const QString &key,
QStringList &value,
QStringList defaultValue)
{
value = defaultValue;
if (!obj.contains(key))
return false;
const QJsonValue &v = obj.value(key);
if (v.isString()) {
value.append(v.toString());
return true;
}
if (v.isArray()) {
const QJsonArray &array = v.toArray();
for (auto &&a : array) {
if (a.isString())
value.append(a.toString());
}
}
return true;
}
bool Policy::jsonGetBool(const QJsonObject &obj, const QString &key, bool &value, bool defaultValue)
{
if (obj.contains(key)) {
const QJsonValue &v = obj.value(key);
if (v.isBool()) {
value = v.toBool();
return true;
}
}
value = defaultValue;
return false;
}
bool Policy::jsonGetInt(const QJsonObject &obj, const QString &key, int &value, int defaultValue)
{
if (obj.contains(key)) {
const QJsonValue &v = obj.value(key);
if (v.isDouble()) {
value = v.toInt();
return true;
}
}
value = defaultValue;
return false;
}