1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "security.h"
17 #include <regex>
18 #include <sys/stat.h>
19 #include <thread>
20 #include <unistd.h>
21 #include "dev_slinfo_mgr.h"
22 #include "device_manager_adapter.h"
23 #include "log_print.h"
24 #include "security_label.h"
25 #include "utils/anonymous.h"
26 
27 #undef LOG_TAG
28 #define LOG_TAG "Security"
29 namespace OHOS::DistributedKv {
30 namespace {
31     constexpr const char *SECURITY_VALUE_XATTR_PARRERN = "s([01234])";
32 }
33 using namespace DistributedDB;
34 using Anonymous = DistributedData::Anonymous;
35 const std::string Security::LABEL_VALUES[S4 + 1] = {
36     "", "s0", "s1", "s2", "s3", "s4"
37 };
Security()38 Security::Security()
39 {
40     ZLOGD("construct");
41 }
42 
~Security()43 Security::~Security()
44 {
45     ZLOGD("destructor");
46 }
47 
GetChangeLevelType() const48 AppDistributedKv::ChangeLevelType Security::GetChangeLevelType() const
49 {
50     return AppDistributedKv::ChangeLevelType::LOW;
51 }
52 
RegOnAccessControlledEvent(const OnAccessControlledEvent & callback)53 DBStatus Security::RegOnAccessControlledEvent(const OnAccessControlledEvent &callback)
54 {
55     ZLOGD("add new lock status observer!");
56     return DBStatus::NOT_SUPPORT;
57 }
58 
IsAccessControlled() const59 bool Security::IsAccessControlled() const
60 {
61     auto curStatus = GetCurrentUserStatus();
62     return !(curStatus == UNLOCK || curStatus == NO_PWD);
63 }
64 
SetSecurityOption(const std::string & filePath,const SecurityOption & option)65 DBStatus Security::SetSecurityOption(const std::string &filePath, const SecurityOption &option)
66 {
67     if (filePath.empty()) {
68         return INVALID_ARGS;
69     }
70 
71     struct stat curStat;
72     stat(filePath.c_str(), &curStat);
73     if (S_ISDIR(curStat.st_mode)) {
74         return SetDirSecurityOption(filePath, option);
75     } else {
76         return SetFileSecurityOption(filePath, option);
77     }
78 }
79 
GetSecurityOption(const std::string & filePath,SecurityOption & option) const80 DBStatus Security::GetSecurityOption(const std::string &filePath, SecurityOption &option) const
81 {
82     if (filePath.empty()) {
83         return INVALID_ARGS;
84     }
85 
86     struct stat curStat;
87     stat(filePath.c_str(), &curStat);
88     if (S_ISDIR(curStat.st_mode)) {
89         return GetDirSecurityOption(filePath, option);
90     } else {
91         return GetFileSecurityOption(filePath, option);
92     }
93 }
94 
CheckDeviceSecurityAbility(const std::string & deviceId,const SecurityOption & option) const95 bool Security::CheckDeviceSecurityAbility(const std::string &deviceId, const SecurityOption &option) const
96 {
97     ZLOGD("The kvstore security level: label:%d", option.securityLabel);
98     Sensitive sensitive = GetSensitiveByUuid(deviceId);
99     return (sensitive >= option);
100 }
101 
Convert2Security(const std::string & name)102 int Security::Convert2Security(const std::string &name)
103 {
104     for (int i = 0; i <= S4; i++) {
105         if (name == LABEL_VALUES[i]) {
106             return i;
107         }
108     }
109     return NOT_SET;
110 }
111 
Convert2Name(const SecurityOption & option)112 const std::string Security::Convert2Name(const SecurityOption &option)
113 {
114     if (option.securityLabel <= NOT_SET || option.securityLabel > S4) {
115         return "";
116     }
117 
118     return LABEL_VALUES[option.securityLabel];
119 }
120 
IsXattrValueValid(const std::string & value) const121 bool Security::IsXattrValueValid(const std::string& value) const
122 {
123     if (value.empty()) {
124         ZLOGD("value is empty");
125         return false;
126     }
127 
128     return std::regex_match(value, std::regex(SECURITY_VALUE_XATTR_PARRERN));
129 }
130 
IsSupportSecurity()131 bool Security::IsSupportSecurity()
132 {
133     return false;
134 }
135 
OnDeviceChanged(const AppDistributedKv::DeviceInfo & info,const AppDistributedKv::DeviceChangeType & type) const136 void Security::OnDeviceChanged(const AppDistributedKv::DeviceInfo &info,
137                                const AppDistributedKv::DeviceChangeType &type) const
138 {
139     if (info.networkId.empty()) {
140         ZLOGD("deviceId is empty");
141         return;
142     }
143 
144     if (info.uuid == DistributedData::DeviceManagerAdapter::CLOUD_DEVICE_UUID) {
145         ZLOGD("This is network change");
146         return;
147     }
148 
149     switch (type) {
150         case AppDistributedKv::DeviceChangeType::DEVICE_OFFLINE:
151             ZLOGD("device is offline, deviceId:%{public}s", Anonymous::Change(info.uuid).c_str());
152             EraseSensitiveByUuid(info.uuid);
153             break;
154         case AppDistributedKv::DeviceChangeType::DEVICE_ONLINE:
155             ZLOGD("device is online, deviceId:%{public}s", Anonymous::Change(info.uuid).c_str());
156             (void)GetSensitiveByUuid(info.uuid);
157             break;
158         default:
159             break;
160     }
161 }
162 
IsExits(const std::string & file) const163 bool Security::IsExits(const std::string &file) const
164 {
165     return access(file.c_str(), F_OK) == 0;
166 }
167 
InitLocalSecurity()168 void Security::InitLocalSecurity()
169 {
170     auto devInfo = DistributedData::DeviceManagerAdapter::GetInstance().GetLocalDevice();
171     GetSensitiveByUuid(devInfo.uuid);
172 }
173 
GetSensitiveByUuid(const std::string & uuid) const174 Sensitive Security::GetSensitiveByUuid(const std::string &uuid) const
175 {
176     auto it = devicesUdid_.Find(uuid);
177     if (!it.first) {
178         executors_->Execute([this, uuid]() {
179             auto iter = devicesUdid_.Find(uuid);
180             if (iter.first) {
181                 return;
182             }
183             auto udid = DistributedData::DeviceManagerAdapter::GetInstance().ToUDID(uuid);
184             if (udid.empty()) {
185                 return;
186             }
187             Sensitive sensitive(udid);
188             auto level = sensitive.GetDeviceSecurityLevel();
189             ZLOGI("udid:%{public}s, uuid:%{public}s, security level:%{public}d",
190                   Anonymous::Change(udid).c_str(), Anonymous::Change(uuid).c_str(), level);
191             devicesUdid_.Insert(uuid, sensitive);
192         });
193     }
194     return it.second;
195 }
196 
EraseSensitiveByUuid(const std::string & uuid) const197 bool Security::EraseSensitiveByUuid(const std::string &uuid) const
198 {
199     devicesUdid_.Erase(uuid);
200     return true;
201 }
202 
GetCurrentUserStatus() const203 int32_t Security::GetCurrentUserStatus() const
204 {
205     return NO_PWD;
206 }
207 
SetFileSecurityOption(const std::string & filePath,const SecurityOption & option)208 DBStatus Security::SetFileSecurityOption(const std::string &filePath, const SecurityOption &option)
209 {
210     if (!IsExits(filePath)) {
211         ZLOGE("option:%{public}d file:%{public}s not exits", option.securityLabel, filePath.c_str());
212         return INVALID_ARGS;
213     }
214     if (option.securityLabel == NOT_SET) {
215         return OK;
216     }
217     auto dataLevel = Convert2Name(option);
218     if (dataLevel.empty()) {
219         ZLOGE("Invalid args! label:%{public}d path:%{public}s", option.securityLabel, filePath.c_str());
220         return INVALID_ARGS;
221     }
222 
223     bool result = OHOS::FileManagement::ModuleSecurityLabel::SecurityLabel::SetSecurityLabel(filePath, dataLevel);
224     if (result) {
225         return OK;
226     }
227 
228     auto error = errno;
229     std::string current = OHOS::FileManagement::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath);
230     ZLOGE("failed! error:%{public}d current:%{public}s label:%{public}s file:%{public}s", error, current.c_str(),
231         dataLevel.c_str(), filePath.c_str());
232     if (current == dataLevel) {
233         return OK;
234     }
235     return DistributedDB::DB_ERROR;
236 }
237 
SetDirSecurityOption(const std::string & filePath,const SecurityOption & option)238 DBStatus Security::SetDirSecurityOption(const std::string &filePath, const SecurityOption &option)
239 {
240     ZLOGI("the filePath is a directory!");
241     (void)filePath;
242     (void)option;
243     return DBStatus::NOT_SUPPORT;
244 }
245 
GetFileSecurityOption(const std::string & filePath,SecurityOption & option) const246 DBStatus Security::GetFileSecurityOption(const std::string &filePath, SecurityOption &option) const
247 {
248     if (!IsExits(filePath)) {
249         option = {NOT_SET, ECE};
250         return OK;
251     }
252 
253     std::string value = OHOS::FileManagement::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath);
254     if (!IsXattrValueValid(value)) {
255         option = {NOT_SET, ECE};
256         return OK;
257     }
258 
259     ZLOGI("get security option %{public}s", value.c_str());
260     if (value == "s3") {
261         option = { Convert2Security(value), SECE };
262     } else {
263         option = { Convert2Security(value), ECE };
264     }
265     return OK;
266 }
267 
GetDirSecurityOption(const std::string & filePath,SecurityOption & option) const268 DBStatus Security::GetDirSecurityOption(const std::string &filePath, SecurityOption &option) const
269 {
270     ZLOGI("the filePath is a directory!");
271     (void)filePath;
272     (void)option;
273     return DBStatus::NOT_SUPPORT;
274 }
275 } // namespace OHOS::DistributedKv
276