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 <unistd.h>
18 #include <thread>
19 #include <algorithm>
20 #include <regex>
21 #include "constant.h"
22 #include "log_print.h"
23 #include "device_manager_adapter.h"
24 #include "dev_slinfo_mgr.h"
25 #include "security_label.h"
26 #include "utils/anonymous.h"
27
28 #undef LOG_TAG
29 #define LOG_TAG "Security"
30 namespace OHOS::DistributedKv {
31 namespace {
32 constexpr const char *SECURITY_VALUE_XATTR_PARRERN = "s([01234])";
33 }
34 using namespace DistributedDB;
35 using Anonymous = DistributedData::Anonymous;
36 const std::string Security::LABEL_VALUES[S4 + 1] = {
37 "", "s0", "s1", "s2", "s3", "s4"
38 };
Security()39 Security::Security()
40 {
41 ZLOGD("construct");
42 }
43
~Security()44 Security::~Security()
45 {
46 ZLOGD("destructor");
47 }
48
GetChangeLevelType() const49 AppDistributedKv::ChangeLevelType Security::GetChangeLevelType() const
50 {
51 return AppDistributedKv::ChangeLevelType::LOW;
52 }
53
RegOnAccessControlledEvent(const OnAccessControlledEvent & callback)54 DBStatus Security::RegOnAccessControlledEvent(const OnAccessControlledEvent &callback)
55 {
56 ZLOGD("add new lock status observer!");
57 return DBStatus::NOT_SUPPORT;
58 }
59
IsAccessControlled() const60 bool Security::IsAccessControlled() const
61 {
62 auto curStatus = GetCurrentUserStatus();
63 return !(curStatus == UNLOCK || curStatus == NO_PWD);
64 }
65
SetSecurityOption(const std::string & filePath,const SecurityOption & option)66 DBStatus Security::SetSecurityOption(const std::string &filePath, const SecurityOption &option)
67 {
68 if (filePath.empty()) {
69 return INVALID_ARGS;
70 }
71
72 struct stat curStat;
73 stat(filePath.c_str(), &curStat);
74 if (S_ISDIR(curStat.st_mode)) {
75 return SetDirSecurityOption(filePath, option);
76 } else {
77 return SetFileSecurityOption(filePath, option);
78 }
79 }
80
GetSecurityOption(const std::string & filePath,SecurityOption & option) const81 DBStatus Security::GetSecurityOption(const std::string &filePath, SecurityOption &option) const
82 {
83 if (filePath.empty()) {
84 return INVALID_ARGS;
85 }
86
87 struct stat curStat;
88 stat(filePath.c_str(), &curStat);
89 if (S_ISDIR(curStat.st_mode)) {
90 return GetDirSecurityOption(filePath, option);
91 } else {
92 return GetFileSecurityOption(filePath, option);
93 }
94 }
95
CheckDeviceSecurityAbility(const std::string & deviceId,const SecurityOption & option) const96 bool Security::CheckDeviceSecurityAbility(const std::string &deviceId, const SecurityOption &option) const
97 {
98 ZLOGD("The kvstore security level: label:%d", option.securityLabel);
99 Sensitive sensitive = GetSensitiveByUuid(deviceId);
100 return (sensitive >= option);
101 }
102
Convert2Security(const std::string & name)103 int Security::Convert2Security(const std::string &name)
104 {
105 for (int i = 0; i <= S4; i++) {
106 if (name == LABEL_VALUES[i]) {
107 return i;
108 }
109 }
110 return NOT_SET;
111 }
112
Convert2Name(const SecurityOption & option)113 const std::string Security::Convert2Name(const SecurityOption &option)
114 {
115 if (option.securityLabel <= NOT_SET || option.securityLabel > S4) {
116 return "";
117 }
118
119 return LABEL_VALUES[option.securityLabel];
120 }
121
IsXattrValueValid(const std::string & value) const122 bool Security::IsXattrValueValid(const std::string& value) const
123 {
124 if (value.empty()) {
125 ZLOGD("value is empty");
126 return false;
127 }
128
129 return std::regex_match(value, std::regex(SECURITY_VALUE_XATTR_PARRERN));
130 }
131
IsSupportSecurity()132 bool Security::IsSupportSecurity()
133 {
134 return false;
135 }
136
OnDeviceChanged(const AppDistributedKv::DeviceInfo & info,const AppDistributedKv::DeviceChangeType & type) const137 void Security::OnDeviceChanged(const AppDistributedKv::DeviceInfo &info,
138 const AppDistributedKv::DeviceChangeType &type) const
139 {
140 if (info.networkId.empty()) {
141 ZLOGD("deviceId is empty");
142 return;
143 }
144
145 bool isOnline = type == AppDistributedKv::DeviceChangeType::DEVICE_ONLINE;
146 if (isOnline) {
147 (void)GetSensitiveByUuid(info.uuid);
148 ZLOGD("device is online, deviceId:%{public}s", Anonymous::Change(info.uuid).c_str());
149 } else {
150 EraseSensitiveByUuid(info.uuid);
151 ZLOGD("device is offline, deviceId:%{public}s", Anonymous::Change(info.uuid).c_str());
152 }
153 }
154
IsExits(const std::string & file) const155 bool Security::IsExits(const std::string &file) const
156 {
157 return access(file.c_str(), F_OK) == 0;
158 }
159
GetSensitiveByUuid(const std::string & uuid) const160 Sensitive Security::GetSensitiveByUuid(const std::string &uuid) const
161 {
162 auto it = devicesUdid_.Find(uuid);
163 if (!it.first) {
164 taskScheduler_.Execute([this, uuid]() {
165 auto it = devicesUdid_.Find(uuid);
166 if (it.first) {
167 return;
168 }
169 auto udid = DistributedData::DeviceManagerAdapter::GetInstance().ToUDID(uuid);
170 if (udid.empty()) {
171 return;
172 }
173 Sensitive sensitive(udid);
174 auto level = sensitive.GetDeviceSecurityLevel();
175 ZLOGI("udid:%{public}s, uuid:%{public}s, security level:%{public}d",
176 Anonymous::Change(udid).c_str(), Anonymous::Change(uuid).c_str(), level);
177 devicesUdid_.Insert(uuid, sensitive);
178 });
179 }
180 return it.second;
181 }
182
EraseSensitiveByUuid(const std::string & uuid) const183 bool Security::EraseSensitiveByUuid(const std::string &uuid) const
184 {
185 devicesUdid_.Erase(uuid);
186 return true;
187 }
188
GetCurrentUserStatus() const189 int32_t Security::GetCurrentUserStatus() const
190 {
191 return NO_PWD;
192 }
193
SetFileSecurityOption(const std::string & filePath,const SecurityOption & option)194 DBStatus Security::SetFileSecurityOption(const std::string &filePath, const SecurityOption &option)
195 {
196 if (!IsExits(filePath)) {
197 ZLOGE("option:%{public}d file:%{public}s not exits", option.securityLabel, filePath.c_str());
198 return INVALID_ARGS;
199 }
200 if (option.securityLabel == NOT_SET) {
201 return OK;
202 }
203 auto dataLevel = Convert2Name(option);
204 if (dataLevel.empty()) {
205 ZLOGE("Invalid args! label:%{public}d path:%{public}s", option.securityLabel, filePath.c_str());
206 return INVALID_ARGS;
207 }
208
209 bool result = OHOS::DistributedFS::ModuleSecurityLabel::SecurityLabel::SetSecurityLabel(filePath, dataLevel);
210 if (result) {
211 return OK;
212 }
213
214 auto error = errno;
215 std::string current = OHOS::DistributedFS::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath);
216 ZLOGE("failed! error:%{public}d current:%{public}s label:%{public}s file:%{public}s", error, current.c_str(),
217 dataLevel.c_str(), filePath.c_str());
218 if (current == dataLevel) {
219 return OK;
220 }
221 return DistributedDB::DB_ERROR;
222 }
223
SetDirSecurityOption(const std::string & filePath,const SecurityOption & option)224 DBStatus Security::SetDirSecurityOption(const std::string &filePath, const SecurityOption &option)
225 {
226 ZLOGI("the filePath is a directory!");
227 (void)filePath;
228 (void)option;
229 return DBStatus::NOT_SUPPORT;
230 }
231
GetFileSecurityOption(const std::string & filePath,SecurityOption & option) const232 DBStatus Security::GetFileSecurityOption(const std::string &filePath, SecurityOption &option) const
233 {
234 if (!IsExits(filePath)) {
235 option = {NOT_SET, ECE};
236 return OK;
237 }
238
239 std::string value = OHOS::DistributedFS::ModuleSecurityLabel::SecurityLabel::GetSecurityLabel(filePath);
240 if (!IsXattrValueValid(value)) {
241 option = {NOT_SET, ECE};
242 return OK;
243 }
244
245 ZLOGI("get security option %{public}s", value.c_str());
246 if (value == "s3") {
247 option = { Convert2Security(value), SECE };
248 } else {
249 option = { Convert2Security(value), ECE };
250 }
251 return OK;
252 }
253
GetDirSecurityOption(const std::string & filePath,SecurityOption & option) const254 DBStatus Security::GetDirSecurityOption(const std::string &filePath, SecurityOption &option) const
255 {
256 ZLOGI("the filePath is a directory!");
257 (void)filePath;
258 (void)option;
259 return DBStatus::NOT_SUPPORT;
260 }
261 } // namespace OHOS::DistributedKv
262