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