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