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 bool isOnline = type == AppDistributedKv::DeviceChangeType::DEVICE_ONLINE;
150 if (isOnline) {
151 (void)GetSensitiveByUuid(info.uuid);
152 ZLOGD("device is online, deviceId:%{public}s", Anonymous::Change(info.uuid).c_str());
153 } else {
154 EraseSensitiveByUuid(info.uuid);
155 ZLOGD("device is offline, deviceId:%{public}s", Anonymous::Change(info.uuid).c_str());
156 }
157 }
158
IsExits(const std::string & file) const159 bool Security::IsExits(const std::string &file) const
160 {
161 return access(file.c_str(), F_OK) == 0;
162 }
163
GetSensitiveByUuid(const std::string & uuid) const164 Sensitive Security::GetSensitiveByUuid(const std::string &uuid) const
165 {
166 auto it = devicesUdid_.Find(uuid);
167 if (!it.first) {
168 executors_->Execute([this, uuid]() {
169 auto iter = devicesUdid_.Find(uuid);
170 if (iter.first) {
171 return;
172 }
173 auto udid = DistributedData::DeviceManagerAdapter::GetInstance().ToUDID(uuid);
174 if (udid.empty()) {
175 return;
176 }
177 Sensitive sensitive(udid);
178 auto level = sensitive.GetDeviceSecurityLevel();
179 ZLOGI("udid:%{public}s, uuid:%{public}s, security level:%{public}d",
180 Anonymous::Change(udid).c_str(), Anonymous::Change(uuid).c_str(), level);
181 devicesUdid_.Insert(uuid, sensitive);
182 });
183 }
184 return it.second;
185 }
186
EraseSensitiveByUuid(const std::string & uuid) const187 bool Security::EraseSensitiveByUuid(const std::string &uuid) const
188 {
189 devicesUdid_.Erase(uuid);
190 return true;
191 }
192
GetCurrentUserStatus() const193 int32_t Security::GetCurrentUserStatus() const
194 {
195 return NO_PWD;
196 }
197
SetFileSecurityOption(const std::string & filePath,const SecurityOption & option)198 DBStatus Security::SetFileSecurityOption(const std::string &filePath, const SecurityOption &option)
199 {
200 if (!IsExits(filePath)) {
201 ZLOGE("option:%{public}d file:%{public}s not exits", option.securityLabel, filePath.c_str());
202 return INVALID_ARGS;
203 }
204 if (option.securityLabel == NOT_SET) {
205 return OK;
206 }
207 auto dataLevel = Convert2Name(option);
208 if (dataLevel.empty()) {
209 ZLOGE("Invalid args! label:%{public}d path:%{public}s", option.securityLabel, filePath.c_str());
210 return INVALID_ARGS;
211 }
212
213 bool result = OHOS::DistributedFS::ModuleSecurityLabel::SecurityLabel::SetSecurityLabel(filePath, dataLevel);
214 if (result) {
215 return OK;
216 }
217
218 auto error = errno;
219 std::string current = OHOS::DistributedFS::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath);
220 ZLOGE("failed! error:%{public}d current:%{public}s label:%{public}s file:%{public}s", error, current.c_str(),
221 dataLevel.c_str(), filePath.c_str());
222 if (current == dataLevel) {
223 return OK;
224 }
225 return DistributedDB::DB_ERROR;
226 }
227
SetDirSecurityOption(const std::string & filePath,const SecurityOption & option)228 DBStatus Security::SetDirSecurityOption(const std::string &filePath, const SecurityOption &option)
229 {
230 ZLOGI("the filePath is a directory!");
231 (void)filePath;
232 (void)option;
233 return DBStatus::NOT_SUPPORT;
234 }
235
GetFileSecurityOption(const std::string & filePath,SecurityOption & option) const236 DBStatus Security::GetFileSecurityOption(const std::string &filePath, SecurityOption &option) const
237 {
238 if (!IsExits(filePath)) {
239 option = {NOT_SET, ECE};
240 return OK;
241 }
242
243 std::string value = OHOS::DistributedFS::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath);
244 if (!IsXattrValueValid(value)) {
245 option = {NOT_SET, ECE};
246 return OK;
247 }
248
249 ZLOGI("get security option %{public}s", value.c_str());
250 if (value == "s3") {
251 option = { Convert2Security(value), SECE };
252 } else {
253 option = { Convert2Security(value), ECE };
254 }
255 return OK;
256 }
257
GetDirSecurityOption(const std::string & filePath,SecurityOption & option) const258 DBStatus Security::GetDirSecurityOption(const std::string &filePath, SecurityOption &option) const
259 {
260 ZLOGI("the filePath is a directory!");
261 (void)filePath;
262 (void)option;
263 return DBStatus::NOT_SUPPORT;
264 }
265 } // namespace OHOS::DistributedKv
266