153c3577eSopenharmony_ci/*
253c3577eSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
353c3577eSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
453c3577eSopenharmony_ci * you may not use this file except in compliance with the License.
553c3577eSopenharmony_ci * You may obtain a copy of the License at
653c3577eSopenharmony_ci *
753c3577eSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
853c3577eSopenharmony_ci *
953c3577eSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1053c3577eSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1153c3577eSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1253c3577eSopenharmony_ci * See the License for the specific language governing permissions and
1353c3577eSopenharmony_ci * limitations under the License.
1453c3577eSopenharmony_ci */
1553c3577eSopenharmony_ci
1653c3577eSopenharmony_ci#include "security.h"
1753c3577eSopenharmony_ci#include <regex>
1853c3577eSopenharmony_ci#include <sys/stat.h>
1953c3577eSopenharmony_ci#include <thread>
2053c3577eSopenharmony_ci#include <unistd.h>
2153c3577eSopenharmony_ci#include "dev_slinfo_mgr.h"
2253c3577eSopenharmony_ci#include "device_manager_adapter.h"
2353c3577eSopenharmony_ci#include "log_print.h"
2453c3577eSopenharmony_ci#include "security_label.h"
2553c3577eSopenharmony_ci#include "utils/anonymous.h"
2653c3577eSopenharmony_ci
2753c3577eSopenharmony_ci#undef LOG_TAG
2853c3577eSopenharmony_ci#define LOG_TAG "Security"
2953c3577eSopenharmony_cinamespace OHOS::DistributedKv {
3053c3577eSopenharmony_cinamespace {
3153c3577eSopenharmony_ci    constexpr const char *SECURITY_VALUE_XATTR_PARRERN = "s([01234])";
3253c3577eSopenharmony_ci}
3353c3577eSopenharmony_ciusing namespace DistributedDB;
3453c3577eSopenharmony_ciusing Anonymous = DistributedData::Anonymous;
3553c3577eSopenharmony_ciconst std::string Security::LABEL_VALUES[S4 + 1] = {
3653c3577eSopenharmony_ci    "", "s0", "s1", "s2", "s3", "s4"
3753c3577eSopenharmony_ci};
3853c3577eSopenharmony_ciSecurity::Security()
3953c3577eSopenharmony_ci{
4053c3577eSopenharmony_ci    ZLOGD("construct");
4153c3577eSopenharmony_ci}
4253c3577eSopenharmony_ci
4353c3577eSopenharmony_ciSecurity::~Security()
4453c3577eSopenharmony_ci{
4553c3577eSopenharmony_ci    ZLOGD("destructor");
4653c3577eSopenharmony_ci}
4753c3577eSopenharmony_ci
4853c3577eSopenharmony_ciAppDistributedKv::ChangeLevelType Security::GetChangeLevelType() const
4953c3577eSopenharmony_ci{
5053c3577eSopenharmony_ci    return AppDistributedKv::ChangeLevelType::LOW;
5153c3577eSopenharmony_ci}
5253c3577eSopenharmony_ci
5353c3577eSopenharmony_ciDBStatus Security::RegOnAccessControlledEvent(const OnAccessControlledEvent &callback)
5453c3577eSopenharmony_ci{
5553c3577eSopenharmony_ci    ZLOGD("add new lock status observer!");
5653c3577eSopenharmony_ci    return DBStatus::NOT_SUPPORT;
5753c3577eSopenharmony_ci}
5853c3577eSopenharmony_ci
5953c3577eSopenharmony_cibool Security::IsAccessControlled() const
6053c3577eSopenharmony_ci{
6153c3577eSopenharmony_ci    auto curStatus = GetCurrentUserStatus();
6253c3577eSopenharmony_ci    return !(curStatus == UNLOCK || curStatus == NO_PWD);
6353c3577eSopenharmony_ci}
6453c3577eSopenharmony_ci
6553c3577eSopenharmony_ciDBStatus Security::SetSecurityOption(const std::string &filePath, const SecurityOption &option)
6653c3577eSopenharmony_ci{
6753c3577eSopenharmony_ci    if (filePath.empty()) {
6853c3577eSopenharmony_ci        return INVALID_ARGS;
6953c3577eSopenharmony_ci    }
7053c3577eSopenharmony_ci
7153c3577eSopenharmony_ci    struct stat curStat;
7253c3577eSopenharmony_ci    stat(filePath.c_str(), &curStat);
7353c3577eSopenharmony_ci    if (S_ISDIR(curStat.st_mode)) {
7453c3577eSopenharmony_ci        return SetDirSecurityOption(filePath, option);
7553c3577eSopenharmony_ci    } else {
7653c3577eSopenharmony_ci        return SetFileSecurityOption(filePath, option);
7753c3577eSopenharmony_ci    }
7853c3577eSopenharmony_ci}
7953c3577eSopenharmony_ci
8053c3577eSopenharmony_ciDBStatus Security::GetSecurityOption(const std::string &filePath, SecurityOption &option) const
8153c3577eSopenharmony_ci{
8253c3577eSopenharmony_ci    if (filePath.empty()) {
8353c3577eSopenharmony_ci        return INVALID_ARGS;
8453c3577eSopenharmony_ci    }
8553c3577eSopenharmony_ci
8653c3577eSopenharmony_ci    struct stat curStat;
8753c3577eSopenharmony_ci    stat(filePath.c_str(), &curStat);
8853c3577eSopenharmony_ci    if (S_ISDIR(curStat.st_mode)) {
8953c3577eSopenharmony_ci        return GetDirSecurityOption(filePath, option);
9053c3577eSopenharmony_ci    } else {
9153c3577eSopenharmony_ci        return GetFileSecurityOption(filePath, option);
9253c3577eSopenharmony_ci    }
9353c3577eSopenharmony_ci}
9453c3577eSopenharmony_ci
9553c3577eSopenharmony_cibool Security::CheckDeviceSecurityAbility(const std::string &deviceId, const SecurityOption &option) const
9653c3577eSopenharmony_ci{
9753c3577eSopenharmony_ci    ZLOGD("The kvstore security level: label:%d", option.securityLabel);
9853c3577eSopenharmony_ci    Sensitive sensitive = GetSensitiveByUuid(deviceId);
9953c3577eSopenharmony_ci    return (sensitive >= option);
10053c3577eSopenharmony_ci}
10153c3577eSopenharmony_ci
10253c3577eSopenharmony_ciint Security::Convert2Security(const std::string &name)
10353c3577eSopenharmony_ci{
10453c3577eSopenharmony_ci    for (int i = 0; i <= S4; i++) {
10553c3577eSopenharmony_ci        if (name == LABEL_VALUES[i]) {
10653c3577eSopenharmony_ci            return i;
10753c3577eSopenharmony_ci        }
10853c3577eSopenharmony_ci    }
10953c3577eSopenharmony_ci    return NOT_SET;
11053c3577eSopenharmony_ci}
11153c3577eSopenharmony_ci
11253c3577eSopenharmony_ciconst std::string Security::Convert2Name(const SecurityOption &option)
11353c3577eSopenharmony_ci{
11453c3577eSopenharmony_ci    if (option.securityLabel <= NOT_SET || option.securityLabel > S4) {
11553c3577eSopenharmony_ci        return "";
11653c3577eSopenharmony_ci    }
11753c3577eSopenharmony_ci
11853c3577eSopenharmony_ci    return LABEL_VALUES[option.securityLabel];
11953c3577eSopenharmony_ci}
12053c3577eSopenharmony_ci
12153c3577eSopenharmony_cibool Security::IsXattrValueValid(const std::string& value) const
12253c3577eSopenharmony_ci{
12353c3577eSopenharmony_ci    if (value.empty()) {
12453c3577eSopenharmony_ci        ZLOGD("value is empty");
12553c3577eSopenharmony_ci        return false;
12653c3577eSopenharmony_ci    }
12753c3577eSopenharmony_ci
12853c3577eSopenharmony_ci    return std::regex_match(value, std::regex(SECURITY_VALUE_XATTR_PARRERN));
12953c3577eSopenharmony_ci}
13053c3577eSopenharmony_ci
13153c3577eSopenharmony_cibool Security::IsSupportSecurity()
13253c3577eSopenharmony_ci{
13353c3577eSopenharmony_ci    return false;
13453c3577eSopenharmony_ci}
13553c3577eSopenharmony_ci
13653c3577eSopenharmony_civoid Security::OnDeviceChanged(const AppDistributedKv::DeviceInfo &info,
13753c3577eSopenharmony_ci                               const AppDistributedKv::DeviceChangeType &type) const
13853c3577eSopenharmony_ci{
13953c3577eSopenharmony_ci    if (info.networkId.empty()) {
14053c3577eSopenharmony_ci        ZLOGD("deviceId is empty");
14153c3577eSopenharmony_ci        return;
14253c3577eSopenharmony_ci    }
14353c3577eSopenharmony_ci
14453c3577eSopenharmony_ci    if (info.uuid == DistributedData::DeviceManagerAdapter::CLOUD_DEVICE_UUID) {
14553c3577eSopenharmony_ci        ZLOGD("This is network change");
14653c3577eSopenharmony_ci        return;
14753c3577eSopenharmony_ci    }
14853c3577eSopenharmony_ci
14953c3577eSopenharmony_ci    switch (type) {
15053c3577eSopenharmony_ci        case AppDistributedKv::DeviceChangeType::DEVICE_OFFLINE:
15153c3577eSopenharmony_ci            ZLOGD("device is offline, deviceId:%{public}s", Anonymous::Change(info.uuid).c_str());
15253c3577eSopenharmony_ci            EraseSensitiveByUuid(info.uuid);
15353c3577eSopenharmony_ci            break;
15453c3577eSopenharmony_ci        case AppDistributedKv::DeviceChangeType::DEVICE_ONLINE:
15553c3577eSopenharmony_ci            ZLOGD("device is online, deviceId:%{public}s", Anonymous::Change(info.uuid).c_str());
15653c3577eSopenharmony_ci            (void)GetSensitiveByUuid(info.uuid);
15753c3577eSopenharmony_ci            break;
15853c3577eSopenharmony_ci        default:
15953c3577eSopenharmony_ci            break;
16053c3577eSopenharmony_ci    }
16153c3577eSopenharmony_ci}
16253c3577eSopenharmony_ci
16353c3577eSopenharmony_cibool Security::IsExits(const std::string &file) const
16453c3577eSopenharmony_ci{
16553c3577eSopenharmony_ci    return access(file.c_str(), F_OK) == 0;
16653c3577eSopenharmony_ci}
16753c3577eSopenharmony_ci
16853c3577eSopenharmony_civoid Security::InitLocalSecurity()
16953c3577eSopenharmony_ci{
17053c3577eSopenharmony_ci    auto devInfo = DistributedData::DeviceManagerAdapter::GetInstance().GetLocalDevice();
17153c3577eSopenharmony_ci    GetSensitiveByUuid(devInfo.uuid);
17253c3577eSopenharmony_ci}
17353c3577eSopenharmony_ci
17453c3577eSopenharmony_ciSensitive Security::GetSensitiveByUuid(const std::string &uuid) const
17553c3577eSopenharmony_ci{
17653c3577eSopenharmony_ci    auto it = devicesUdid_.Find(uuid);
17753c3577eSopenharmony_ci    if (!it.first) {
17853c3577eSopenharmony_ci        executors_->Execute([this, uuid]() {
17953c3577eSopenharmony_ci            auto iter = devicesUdid_.Find(uuid);
18053c3577eSopenharmony_ci            if (iter.first) {
18153c3577eSopenharmony_ci                return;
18253c3577eSopenharmony_ci            }
18353c3577eSopenharmony_ci            auto udid = DistributedData::DeviceManagerAdapter::GetInstance().ToUDID(uuid);
18453c3577eSopenharmony_ci            if (udid.empty()) {
18553c3577eSopenharmony_ci                return;
18653c3577eSopenharmony_ci            }
18753c3577eSopenharmony_ci            Sensitive sensitive(udid);
18853c3577eSopenharmony_ci            auto level = sensitive.GetDeviceSecurityLevel();
18953c3577eSopenharmony_ci            ZLOGI("udid:%{public}s, uuid:%{public}s, security level:%{public}d",
19053c3577eSopenharmony_ci                  Anonymous::Change(udid).c_str(), Anonymous::Change(uuid).c_str(), level);
19153c3577eSopenharmony_ci            devicesUdid_.Insert(uuid, sensitive);
19253c3577eSopenharmony_ci        });
19353c3577eSopenharmony_ci    }
19453c3577eSopenharmony_ci    return it.second;
19553c3577eSopenharmony_ci}
19653c3577eSopenharmony_ci
19753c3577eSopenharmony_cibool Security::EraseSensitiveByUuid(const std::string &uuid) const
19853c3577eSopenharmony_ci{
19953c3577eSopenharmony_ci    devicesUdid_.Erase(uuid);
20053c3577eSopenharmony_ci    return true;
20153c3577eSopenharmony_ci}
20253c3577eSopenharmony_ci
20353c3577eSopenharmony_ciint32_t Security::GetCurrentUserStatus() const
20453c3577eSopenharmony_ci{
20553c3577eSopenharmony_ci    return NO_PWD;
20653c3577eSopenharmony_ci}
20753c3577eSopenharmony_ci
20853c3577eSopenharmony_ciDBStatus Security::SetFileSecurityOption(const std::string &filePath, const SecurityOption &option)
20953c3577eSopenharmony_ci{
21053c3577eSopenharmony_ci    if (!IsExits(filePath)) {
21153c3577eSopenharmony_ci        ZLOGE("option:%{public}d file:%{public}s not exits", option.securityLabel, filePath.c_str());
21253c3577eSopenharmony_ci        return INVALID_ARGS;
21353c3577eSopenharmony_ci    }
21453c3577eSopenharmony_ci    if (option.securityLabel == NOT_SET) {
21553c3577eSopenharmony_ci        return OK;
21653c3577eSopenharmony_ci    }
21753c3577eSopenharmony_ci    auto dataLevel = Convert2Name(option);
21853c3577eSopenharmony_ci    if (dataLevel.empty()) {
21953c3577eSopenharmony_ci        ZLOGE("Invalid args! label:%{public}d path:%{public}s", option.securityLabel, filePath.c_str());
22053c3577eSopenharmony_ci        return INVALID_ARGS;
22153c3577eSopenharmony_ci    }
22253c3577eSopenharmony_ci
22353c3577eSopenharmony_ci    bool result = OHOS::FileManagement::ModuleSecurityLabel::SecurityLabel::SetSecurityLabel(filePath, dataLevel);
22453c3577eSopenharmony_ci    if (result) {
22553c3577eSopenharmony_ci        return OK;
22653c3577eSopenharmony_ci    }
22753c3577eSopenharmony_ci
22853c3577eSopenharmony_ci    auto error = errno;
22953c3577eSopenharmony_ci    std::string current = OHOS::FileManagement::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath);
23053c3577eSopenharmony_ci    ZLOGE("failed! error:%{public}d current:%{public}s label:%{public}s file:%{public}s", error, current.c_str(),
23153c3577eSopenharmony_ci        dataLevel.c_str(), filePath.c_str());
23253c3577eSopenharmony_ci    if (current == dataLevel) {
23353c3577eSopenharmony_ci        return OK;
23453c3577eSopenharmony_ci    }
23553c3577eSopenharmony_ci    return DistributedDB::DB_ERROR;
23653c3577eSopenharmony_ci}
23753c3577eSopenharmony_ci
23853c3577eSopenharmony_ciDBStatus Security::SetDirSecurityOption(const std::string &filePath, const SecurityOption &option)
23953c3577eSopenharmony_ci{
24053c3577eSopenharmony_ci    ZLOGI("the filePath is a directory!");
24153c3577eSopenharmony_ci    (void)filePath;
24253c3577eSopenharmony_ci    (void)option;
24353c3577eSopenharmony_ci    return DBStatus::NOT_SUPPORT;
24453c3577eSopenharmony_ci}
24553c3577eSopenharmony_ci
24653c3577eSopenharmony_ciDBStatus Security::GetFileSecurityOption(const std::string &filePath, SecurityOption &option) const
24753c3577eSopenharmony_ci{
24853c3577eSopenharmony_ci    if (!IsExits(filePath)) {
24953c3577eSopenharmony_ci        option = {NOT_SET, ECE};
25053c3577eSopenharmony_ci        return OK;
25153c3577eSopenharmony_ci    }
25253c3577eSopenharmony_ci
25353c3577eSopenharmony_ci    std::string value = OHOS::FileManagement::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath);
25453c3577eSopenharmony_ci    if (!IsXattrValueValid(value)) {
25553c3577eSopenharmony_ci        option = {NOT_SET, ECE};
25653c3577eSopenharmony_ci        return OK;
25753c3577eSopenharmony_ci    }
25853c3577eSopenharmony_ci
25953c3577eSopenharmony_ci    ZLOGI("get security option %{public}s", value.c_str());
26053c3577eSopenharmony_ci    if (value == "s3") {
26153c3577eSopenharmony_ci        option = { Convert2Security(value), SECE };
26253c3577eSopenharmony_ci    } else {
26353c3577eSopenharmony_ci        option = { Convert2Security(value), ECE };
26453c3577eSopenharmony_ci    }
26553c3577eSopenharmony_ci    return OK;
26653c3577eSopenharmony_ci}
26753c3577eSopenharmony_ci
26853c3577eSopenharmony_ciDBStatus Security::GetDirSecurityOption(const std::string &filePath, SecurityOption &option) const
26953c3577eSopenharmony_ci{
27053c3577eSopenharmony_ci    ZLOGI("the filePath is a directory!");
27153c3577eSopenharmony_ci    (void)filePath;
27253c3577eSopenharmony_ci    (void)option;
27353c3577eSopenharmony_ci    return DBStatus::NOT_SUPPORT;
27453c3577eSopenharmony_ci}
27553c3577eSopenharmony_ci} // namespace OHOS::DistributedKv
276