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