1 /*
2 * Copyright (c) 2022 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 "authority_manager.h"
17
18 #include <fstream>
19
20 #include "accesstoken_kit.h"
21 #include "file_ex.h"
22 #include "ipc_skeleton.h"
23 #include "securec.h"
24
25 #include "device_profile_log.h"
26
27 namespace OHOS {
28 namespace DeviceProfile {
29 using namespace OHOS::Security::AccessToken;
30
31 namespace {
32 const std::string TAG = "AuthorityManager";
33
34 constexpr uint32_t INVALID_TOKEN_ID = 0;
35 const std::string INTERFACES = "interfacesAuthority";
36 const std::string SERVICES = "servicesAuthority";
37 const std::string SERVICES_ALL = "all";
38 const std::string SERVICES_SPECIFIC = "specific";
39 const std::string SERVICES_PREFIX = "prefix";
40 const std::string AUTHORITY_JSON_PATH = "/system/etc/deviceprofile/authority.json";
41 }
42
43 IMPLEMENT_SINGLE_INSTANCE(AuthorityManager);
44
Init()45 bool AuthorityManager::Init()
46 {
47 if (!LoadAuthorityCfg(AUTHORITY_JSON_PATH)) {
48 return false;
49 }
50 InitSupportedInterfaces();
51 ValidateAuthorityCfg();
52 HILOGI("init succeeded");
53 return true;
54 }
55
InitSupportedInterfaces()56 void AuthorityManager::InitSupportedInterfaces()
57 {
58 supportedInterfaces_ = { "sync" };
59 }
60
LoadAuthorityCfg(const std::string & filePath)61 bool AuthorityManager::LoadAuthorityCfg(const std::string& filePath)
62 {
63 std::ifstream ifs(filePath.c_str());
64 if (!ifs.good()) {
65 HILOGE("load json file failed");
66 return false;
67 }
68 authJson_ = nlohmann::json::parse(ifs, nullptr, false);
69 if (authJson_.is_discarded()) {
70 HILOGE("parse failed");
71 return false;
72 }
73 return true;
74 }
75
ValidateAuthorityCfg()76 void AuthorityManager::ValidateAuthorityCfg()
77 {
78 for (auto iter = authJson_.begin(); iter != authJson_.end();) {
79 if (!ValidateProcess(iter.value())) {
80 HILOGE("authority for proc %{public}s is invalid, deleted", iter.key().c_str());
81 authJson_.erase(iter++);
82 } else {
83 iter++;
84 }
85 }
86 }
87
ValidateProcess(nlohmann::json & processJson)88 bool AuthorityManager::ValidateProcess(nlohmann::json& processJson)
89 {
90 for (auto& [key, value] : processJson.items()) {
91 if (key != INTERFACES && key != SERVICES) {
92 HILOGE("invalid key:%{public}s under proc", key.c_str());
93 return false;
94 }
95 if (key == INTERFACES && !ValidateInterfaces(value)) {
96 return false;
97 }
98 if (key == SERVICES && !ValidateServices(value)) {
99 return false;
100 }
101 }
102 return true;
103 }
104
ValidateInterfaces(nlohmann::json & interfacesJson)105 bool AuthorityManager::ValidateInterfaces(nlohmann::json& interfacesJson)
106 {
107 if (interfacesJson.empty()) {
108 return false;
109 }
110
111 for (auto& [key, value] : interfacesJson.items()) {
112 if (supportedInterfaces_.find(key) == supportedInterfaces_.end()) {
113 return false;
114 }
115 // value should be type of object, e.g. "sync": {}
116 if (!value.is_object()) {
117 return false;
118 }
119 }
120 return true;
121 }
122
ValidateServices(nlohmann::json & servicesJson)123 bool AuthorityManager::ValidateServices(nlohmann::json& servicesJson)
124 {
125 if (servicesJson.empty()) {
126 return false;
127 }
128
129 if (servicesJson.contains(SERVICES_ALL)) {
130 // currently only read permission is allowed being with SERVICES_ALL
131 if (!ValidateService(servicesJson[SERVICES_ALL], true)) {
132 return false;
133 }
134 }
135
136 if (servicesJson.contains(SERVICES_SPECIFIC) &&
137 !ValidateServicesHelper(servicesJson[SERVICES_SPECIFIC])) {
138 return false;
139 }
140 if (servicesJson.contains(SERVICES_PREFIX) &&
141 !ValidateServicesHelper(servicesJson[SERVICES_PREFIX])) {
142 return false;
143 }
144 return true;
145 }
146
ValidateServicesHelper(nlohmann::json & servicesJson)147 bool AuthorityManager::ValidateServicesHelper(nlohmann::json& servicesJson)
148 {
149 for (auto& [key, value] : servicesJson.items()) {
150 if (!ValidateService(value, false)) {
151 HILOGW("service:%{public}s is invalid, deleted", key.c_str());
152 return false;
153 }
154 }
155 return true;
156 }
157
ValidateService(const nlohmann::json & authValJson,bool readOnly)158 bool AuthorityManager::ValidateService(const nlohmann::json& authValJson, bool readOnly)
159 {
160 if (!authValJson.is_number_unsigned()) {
161 HILOGE("not number type");
162 return false;
163 }
164 auto authVal = authValJson.get<uint32_t>();
165 // single AUTH_W is meaningless and disallowed
166 if (authVal != AuthValue::AUTH_RW &&
167 authVal != AuthValue::AUTH_R) {
168 HILOGE("invalid auth value");
169 return false;
170 }
171 if (readOnly && authVal != AuthValue::AUTH_R) {
172 HILOGE("read only");
173 return false;
174 }
175 return true;
176 }
177
CheckInterfaceAuthority(const std::string & ifaceName)178 bool AuthorityManager::CheckInterfaceAuthority(const std::string& ifaceName)
179 {
180 std::string procName = GetCallingProcName();
181 if (!authJson_.contains(procName)) {
182 HILOGE("can't find entry for proc:%{public}s", procName.c_str());
183 return false;
184 }
185
186 auto& interfacesJson = authJson_[procName][INTERFACES];
187 if (interfacesJson == nullptr) {
188 HILOGE("can't find interfaces entry");
189 return false;
190 }
191
192 if (!interfacesJson.contains(ifaceName)) {
193 HILOGE("%{public}s is disallowed for %{public}s", ifaceName.c_str(),
194 procName.c_str());
195 return false;
196 }
197 return true;
198 }
199
CheckServiceAuthority(AuthValue authVal,const std::string & serviceId)200 bool AuthorityManager::CheckServiceAuthority(AuthValue authVal,
201 const std::string& serviceId)
202 {
203 return CheckServicesAuthority(authVal, { serviceId });
204 }
205
CheckServicesAuthority(AuthValue authVal,const std::vector<std::string> & serviceIds)206 bool AuthorityManager::CheckServicesAuthority(AuthValue authVal,
207 const std::vector<std::string>& serviceIds)
208 {
209 bool hasEmpty = std::any_of(serviceIds.begin(), serviceIds.end(),
210 [](const auto& serviceId) { return serviceId.empty(); });
211 if (hasEmpty) {
212 HILOGE("empty serviceId");
213 return false;
214 }
215
216 std::string procName = GetCallingProcName();
217 if (!authJson_.contains(procName)) {
218 HILOGE("can't find entry for proc:%{public}s", procName.c_str());
219 return false;
220 }
221 auto& servicesJson = authJson_[procName][SERVICES];
222 if (servicesJson == nullptr) {
223 HILOGE("can't find services entry");
224 return false;
225 }
226
227 if (!CheckServicesAuth(servicesJson, authVal, serviceIds)) {
228 return false;
229 }
230 return true;
231 }
232
CheckServicesAuth(const nlohmann::json & servicesJson,AuthValue authVal,const std::vector<std::string> & serviceIds)233 bool AuthorityManager::CheckServicesAuth(const nlohmann::json& servicesJson,
234 AuthValue authVal, const std::vector<std::string>& serviceIds)
235 {
236 bool isReadWithAll = (authVal == AuthValue::AUTH_R) && servicesJson.contains(SERVICES_ALL);
237 if (serviceIds.empty()) {
238 // in case where no serviceIds provided, which means all services; but
239 // SERVICES_ALL is only allowed with AUTH_R
240 return isReadWithAll;
241 }
242 if (isReadWithAll) {
243 HILOGI("check pass, SERVICES_ALL with read");
244 return true;
245 }
246
247 const auto& specificSvcsJson = servicesJson.contains(SERVICES_SPECIFIC) ?
248 servicesJson[SERVICES_SPECIFIC] : nlohmann::json {};
249 const auto& prefixSvcsJson = servicesJson.contains(SERVICES_PREFIX) ?
250 servicesJson[SERVICES_PREFIX] : nlohmann::json {};
251 if (specificSvcsJson == nullptr && prefixSvcsJson == nullptr) {
252 HILOGE("check failed, no specific and prefix service");
253 return false;
254 }
255 for (const auto& serviceId : serviceIds) {
256 if ((specificSvcsJson != nullptr) &&
257 CheckSpecificServiceAuth(specificSvcsJson, serviceId, authVal)) {
258 continue;
259 }
260 if ((prefixSvcsJson != nullptr) &&
261 CheckPrefixServiceAuth(prefixSvcsJson, serviceId, authVal)) {
262 continue;
263 }
264 HILOGE("denied to access service:%{public}s", serviceId.c_str());
265 return false;
266 }
267 HILOGI("check pass, authorities statisfied");
268 return true;
269 }
270
CheckSpecificServiceAuth(const nlohmann::json & specificSvcsJson,const std::string & serviceId,AuthValue authVal)271 bool AuthorityManager::CheckSpecificServiceAuth(const nlohmann::json& specificSvcsJson,
272 const std::string& serviceId, AuthValue authVal)
273 {
274 if (!specificSvcsJson.contains(serviceId)) {
275 return false;
276 }
277 auto& authValJson = specificSvcsJson[serviceId];
278 if (!authValJson.is_number_unsigned()) {
279 HILOGE("not number type");
280 return false;
281 }
282 return ((authValJson.get<uint32_t>() & authVal) != 0);
283 }
284
CheckPrefixServiceAuth(const nlohmann::json & prefixSvcsJson,const std::string & serviceId,AuthValue authVal)285 bool AuthorityManager::CheckPrefixServiceAuth(const nlohmann::json& prefixSvcsJson,
286 const std::string& serviceId, AuthValue authVal)
287 {
288 for (auto& [prefixSvcId, authValJson] : prefixSvcsJson.items()) {
289 if ((serviceId.compare(0, prefixSvcId.size(), prefixSvcId) == 0)) {
290 HILOGI("service:%{public}s, prefix:%{public}s", serviceId.c_str(), prefixSvcId.c_str());
291 if (!authValJson.is_number_unsigned()) {
292 HILOGE("not number type");
293 return false;
294 }
295 return ((authValJson.get<uint32_t>() & authVal) != 0);
296 }
297 }
298 return false;
299 }
300
CheckCallerTrust()301 bool AuthorityManager::CheckCallerTrust()
302 {
303 auto tokenID = IPCSkeleton::GetCallingTokenID();
304 if (tokenID == INVALID_TOKEN_ID) {
305 HILOGW("invalid token id");
306 return false;
307 }
308 ATokenTypeEnum tokenType = AccessTokenKit::GetTokenTypeFlag(tokenID);
309 HILOGD("tokenID:%{public}u, tokenType:%{public}d", tokenID, tokenType);
310 // currently only support native trusted caller
311 return tokenType == ATokenTypeEnum::TOKEN_NATIVE;
312 }
313
GetCallingProcName()314 std::string AuthorityManager::GetCallingProcName()
315 {
316 // called after CheckCallerTrust, and keep same policy with CheckCallerTrust
317 NativeTokenInfo nativeTokenInfo;
318 auto tokenID = IPCSkeleton::GetCallingTokenID();
319 auto errCode = AccessTokenKit::GetNativeTokenInfo(tokenID, nativeTokenInfo);
320 HILOGI("get token info errCode = %{public}d", errCode);
321 std::string procName;
322 if (errCode == EOK) {
323 procName = std::move(nativeTokenInfo.processName);
324 HILOGI("procName:%{public}s", procName.c_str());
325 }
326 return procName;
327 }
328 } // namespace DeviceProfile
329 } // namespace OHOS
330