• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "distributed_sched_permission.h"
17 
18 #include "accesstoken_kit.h"
19 #include "adapter/dnetwork_adapter.h"
20 #include "bundle/bundle_manager_internal.h"
21 #include "caller_info.h"
22 #include "datetime_ex.h"
23 #include "device_auth_defines.h"
24 #include "distributed_sched_adapter.h"
25 #include "dtbschedmgr_log.h"
26 #include "ipc_skeleton.h"
27 
28 namespace OHOS {
29 namespace DistributedSchedule {
30 using namespace OHOS::Security;
31 namespace {
32 const std::string TAG = "DistributedSchedPermission";
33 const std::string FOUNDATION_PROCESS_NAME = "foundation";
34 }
35 IMPLEMENT_SINGLE_INSTANCE(DistributedSchedPermission);
from_json(const nlohmann::json & jsonObject,GroupInfo & groupInfo)36 void from_json(const nlohmann::json& jsonObject, GroupInfo& groupInfo)
37 {
38     if (jsonObject.find(FIELD_GROUP_NAME) != jsonObject.end()) {
39         jsonObject.at(FIELD_GROUP_NAME).get_to(groupInfo.groupName);
40     }
41     if (jsonObject.find(FIELD_GROUP_ID) != jsonObject.end()) {
42         jsonObject.at(FIELD_GROUP_ID).get_to(groupInfo.groupId);
43     }
44     if (jsonObject.find(FIELD_GROUP_OWNER) != jsonObject.end()) {
45         jsonObject.at(FIELD_GROUP_OWNER).get_to(groupInfo.groupOwner);
46     }
47     if (jsonObject.find(FIELD_GROUP_TYPE) != jsonObject.end()) {
48         jsonObject.at(FIELD_GROUP_TYPE).get_to(groupInfo.groupType);
49     }
50     if (jsonObject.find(FIELD_GROUP_VISIBILITY) != jsonObject.end()) {
51         jsonObject.at(FIELD_GROUP_VISIBILITY).get_to(groupInfo.groupVisibility);
52     }
53 }
54 
CheckDPermission(const AAFwk::Want & want,const CallerInfo & callerInfo,const AccountInfo & accountInfo,const AppExecFwk::AbilityInfo & abilityInfo,const std::string & localDeviceId)55 int32_t DistributedSchedPermission::CheckDPermission(const AAFwk::Want& want, const CallerInfo& callerInfo,
56     const AccountInfo& accountInfo, const AppExecFwk::AbilityInfo& abilityInfo, const std::string& localDeviceId)
57 {
58     if (localDeviceId.empty()) {
59         return INVALID_PARAMETERS_ERR;
60     }
61     AppExecFwk::AbilityInfo targetAbility;
62     bool result = getTargetAbility(want, abilityInfo, localDeviceId, targetAbility, callerInfo);
63     if (!result) {
64         HILOGE("CheckDPermission can not find the target ability");
65         return INVALID_PARAMETERS_ERR;
66     }
67     HILOGD("target ability info bundleName:%{public}s abilityName:%{public}s uri:%{private}s visible:%{public}d",
68         targetAbility.bundleName.c_str(), targetAbility.name.c_str(), targetAbility.uri.c_str(),
69         targetAbility.visible);
70     HILOGD("callerType:%{public}d accountType:%{public}d callerUid:%{public}d AccessTokenID:%{public}u",
71         callerInfo.callerType, accountInfo.accountType, callerInfo.uid, callerInfo.accessToken);
72     // 1.check account access permission in no account networking environment.
73     if (!CheckAccountAccessPermission(callerInfo, accountInfo, targetAbility.bundleName)) {
74         HILOGE("CheckAccountAccessPermission denied or failed!");
75         return DMS_ACCOUNT_ACCESS_PERMISSION_DENIED;
76     }
77     // 2.check component access permission, when the ability is not visible.
78     if (!CheckComponentAccessPermission(targetAbility, callerInfo, accountInfo, want)) {
79         HILOGE("CheckComponentAccessPermission denied or failed! the callee component do not have permission");
80         return DMS_COMPONENT_ACCESS_PERMISSION_DENIED;
81     }
82     // 3.check application custom permissions
83     if (!CheckCustomPermission(targetAbility, callerInfo)) {
84         HILOGE("CheckCustomPermission denied or failed! the caller component do not have permission");
85         return DMS_COMPONENT_ACCESS_PERMISSION_DENIED;
86     }
87     HILOGI("CheckDPermission success!!");
88     return ERR_OK;
89 }
90 
GetAccountInfo(const std::string & remoteNetworkId,const CallerInfo & callerInfo,AccountInfo & accountInfo)91 int32_t DistributedSchedPermission::GetAccountInfo(const std::string& remoteNetworkId,
92     const CallerInfo& callerInfo, AccountInfo& accountInfo)
93 {
94     if (remoteNetworkId.empty()) {
95         HILOGE("remoteNetworkId is empty");
96         return ERR_NULL_OBJECT;
97     }
98     std::string udid = DnetworkAdapter::GetInstance()->GetUdidByNetworkId(remoteNetworkId);
99     if (udid.empty()) {
100         HILOGE("udid is empty");
101         return ERR_NULL_OBJECT;
102     }
103     if (!GetRelatedGroups(udid, callerInfo.bundleNames, accountInfo)) {
104         HILOGE("GetRelatedGroups failed");
105         return INVALID_PARAMETERS_ERR;
106     }
107     return ERR_OK;
108 }
109 
GetRelatedGroups(const std::string & udid,const std::vector<std::string> & bundleNames,AccountInfo & accountInfo)110 bool DistributedSchedPermission::GetRelatedGroups(const std::string& udid,
111     const std::vector<std::string>& bundleNames, AccountInfo& accountInfo)
112 {
113     for (const auto& bundleName : bundleNames) {
114         std::string returnGroups;
115         if (!DistributedSchedAdapter::GetInstance().GetRelatedGroups(udid, bundleName, returnGroups)) {
116             continue;
117         }
118         std::vector<GroupInfo> groupInfos;
119         if (!ParseGroupInfos(returnGroups, groupInfos)) {
120             continue;
121         }
122         for (const auto& groupInfo : groupInfos) {
123             // check group type is whether (same count or point to point) or not
124             if (groupInfo.groupType != GroupType::IDENTICAL_ACCOUNT_GROUP
125                 && groupInfo.groupType != GroupType::PEER_TO_PEER_GROUP) {
126                 continue;
127             }
128             accountInfo.groupIdList.push_back(groupInfo.groupId);
129             if (groupInfo.groupType == GroupType::IDENTICAL_ACCOUNT_GROUP
130                 && accountInfo.accountType != IDistributedSched::SAME_ACCOUNT_TYPE) {
131                 accountInfo.accountType = IDistributedSched::SAME_ACCOUNT_TYPE;
132             }
133         }
134     }
135     if (accountInfo.groupIdList.empty()) {
136         HILOGE("groupIdList is empty");
137         return false;
138     }
139     return true;
140 }
141 
ParseGroupInfos(const std::string & returnGroupStr,std::vector<GroupInfo> & groupInfos)142 bool DistributedSchedPermission::ParseGroupInfos(const std::string& returnGroupStr, std::vector<GroupInfo>& groupInfos)
143 {
144     nlohmann::json groupInfoJson = nlohmann::json::parse(returnGroupStr, nullptr, false);
145     if (groupInfoJson.is_discarded()) {
146         HILOGE("returnGroupStr parse failed");
147         return false;
148     }
149     HILOGD("groupInfoJson:%{public}s", groupInfoJson.dump().c_str());
150     groupInfos = groupInfoJson.get<std::vector<GroupInfo>>();
151     if (groupInfos.empty()) {
152         HILOGE("groupInfos is empty");
153         return false;
154     }
155     return true;
156 }
157 
getTargetAbility(const AAFwk::Want & want,const AppExecFwk::AbilityInfo & abilityInfo,const std::string & localDeviceId,AppExecFwk::AbilityInfo & targetAbility,const CallerInfo & callerInfo) const158 bool DistributedSchedPermission::getTargetAbility(const AAFwk::Want& want,
159     const AppExecFwk::AbilityInfo& abilityInfo, const std::string& localDeviceId,
160     AppExecFwk::AbilityInfo& targetAbility, const CallerInfo& callerInfo) const
161 {
162     if (!BundleManagerInternal::QueryAbilityInfo(want, targetAbility)) {
163         HILOGE("QueryAbilityInfo failed");
164         return false;
165     }
166     return true;
167 }
168 
CheckGetCallerPermission(const AAFwk::Want & want,const CallerInfo & callerInfo,const AccountInfo & accountInfo,const std::string & localDeviceId)169 int32_t DistributedSchedPermission::CheckGetCallerPermission(const AAFwk::Want& want, const CallerInfo& callerInfo,
170     const AccountInfo& accountInfo, const std::string& localDeviceId)
171 {
172     AppExecFwk::AbilityInfo abilityInfo;
173     int32_t result = CheckDPermission(want, callerInfo, accountInfo, abilityInfo, localDeviceId);
174     if (result != ERR_OK) {
175         HILOGE("CheckGetCallerPermission fail, error:%{public}d", result);
176         return result;
177     }
178     std::string appId;
179     if (!BundleManagerInternal::GetCallerAppIdFromBms(want.GetElement().GetBundleName(), appId)) {
180         HILOGE("CheckGetCallerPermission get appId fail");
181         return CALL_PERMISSION_DENIED;
182     }
183     if (appId != callerInfo.callerAppId) {
184         HILOGE("CheckGetCallerPermission appId is different");
185         return CALL_PERMISSION_DENIED;
186     }
187     return ERR_OK;
188 }
189 
CheckPermission(uint32_t accessToken,const std::string & permissionName) const190 int32_t DistributedSchedPermission::CheckPermission(uint32_t accessToken, const std::string& permissionName) const
191 {
192     HILOGI("called.");
193     if (!IsFoundationCall(IPCSkeleton::GetCallingTokenID())) {
194         return DMS_PERMISSION_DENIED;
195     }
196     if (IsNativeCall(accessToken)) {
197         return ERR_OK;
198     }
199     if (VerifyPermission(accessToken, permissionName)) {
200         return ERR_OK;
201     }
202     return DMS_PERMISSION_DENIED;
203 }
204 
IsFoundationCall(uint32_t accessToken) const205 bool DistributedSchedPermission::IsFoundationCall(uint32_t accessToken) const
206 {
207     if (!IsNativeCall(accessToken)) {
208         return false;
209     }
210     AccessToken::NativeTokenInfo nativeTokenInfo;
211     int32_t result = AccessToken::AccessTokenKit::GetNativeTokenInfo(accessToken, nativeTokenInfo);
212     if (result == ERR_OK && nativeTokenInfo.processName == FOUNDATION_PROCESS_NAME) {
213         return true;
214     }
215     HILOGE("not foundation called, processName:%{private}s", nativeTokenInfo.processName.c_str());
216     return false;
217 }
218 
IsNativeCall(uint32_t accessToken) const219 bool DistributedSchedPermission::IsNativeCall(uint32_t accessToken) const
220 {
221     auto tokenType = AccessToken::AccessTokenKit::GetTokenTypeFlag(accessToken);
222     if (tokenType == AccessToken::ATokenTypeEnum::TOKEN_NATIVE) {
223         return true;
224     }
225     HILOGE("not native called.");
226     return false;
227 }
228 
VerifyPermission(uint32_t accessToken,const std::string & permissionName) const229 bool DistributedSchedPermission::VerifyPermission(uint32_t accessToken, const std::string& permissionName) const
230 {
231     int32_t result = AccessToken::AccessTokenKit::VerifyAccessToken(accessToken, permissionName);
232     if (result == AccessToken::PermissionState::PERMISSION_DENIED) {
233         HILOGE("permission denied, permissionName:%{public}s", permissionName.c_str());
234         return false;
235     }
236     HILOGD("permission matched.");
237     return true;
238 }
239 
CheckAccountAccessPermission(const CallerInfo & callerInfo,const AccountInfo & accountInfo,const std::string & targetBundleName)240 bool DistributedSchedPermission::CheckAccountAccessPermission(const CallerInfo& callerInfo,
241     const AccountInfo& accountInfo, const std::string& targetBundleName)
242 {
243     if (accountInfo.accountType == IDistributedSched::SAME_ACCOUNT_TYPE) {
244         HILOGD("no need to check");
245         return true;
246     }
247     if (targetBundleName.empty() || accountInfo.groupIdList.empty()) {
248         HILOGE("targetBundleName or groupIdList is empty");
249         return false;
250     }
251 
252     for (const auto& groupId : accountInfo.groupIdList) {
253         HILOGD("groupId:%{public}s targetBundleName:%{public}s", groupId.c_str(), targetBundleName.c_str());
254         if (DistributedSchedAdapter::GetInstance().CheckAccessToGroup(groupId, targetBundleName)) {
255             return true;
256         }
257     }
258     HILOGE("check account permission failed");
259     return false;
260 }
261 
CheckComponentAccessPermission(const AppExecFwk::AbilityInfo & targetAbility,const CallerInfo & callerInfo,const AccountInfo & accountInfo,const AAFwk::Want & want) const262 bool DistributedSchedPermission::CheckComponentAccessPermission(const AppExecFwk::AbilityInfo& targetAbility,
263     const CallerInfo& callerInfo, const AccountInfo& accountInfo, const AAFwk::Want& want) const
264 {
265     // reject directly when in no account networking environment and target ability is not visible,
266     if (!targetAbility.visible) {
267         HILOGE("target ability is not visible, permission denied!");
268         return false;
269     }
270     // when in the migration scenario, make sure the appId is the same.
271     if ((want.GetFlags() & AAFwk::Want::FLAG_ABILITY_CONTINUATION) != 0
272         && !BundleManagerInternal::IsSameAppId(callerInfo.callerAppId, targetAbility.bundleName)) {
273         HILOGE("the appId is different in the migration scenario, permission denied!");
274         return false;
275     }
276     HILOGD("check component permission success");
277     return true;
278 }
279 
CheckCustomPermission(const AppExecFwk::AbilityInfo & targetAbility,const CallerInfo & callerInfo) const280 bool DistributedSchedPermission::CheckCustomPermission(const AppExecFwk::AbilityInfo& targetAbility,
281     const CallerInfo& callerInfo) const
282 {
283     const auto& permissions = targetAbility.permissions;
284     if (permissions.empty()) {
285         HILOGD("no need any permission, so granted!");
286         return true;
287     }
288     if (callerInfo.accessToken == 0) {
289         HILOGW("kernel is not support or field is not parsed, so denied!");
290         return false;
291     }
292     int64_t begin = GetTickCount();
293     uint32_t dAccessToken = AccessToken::AccessTokenKit::AllocLocalTokenID(
294         callerInfo.sourceDeviceId, callerInfo.accessToken);
295     HILOGI("[PerformanceTest] AllocLocalTokenID spend %{public}" PRId64 " ms", GetTickCount() - begin);
296     if (dAccessToken == 0) {
297         HILOGE("dAccessTokenID is invalid!");
298         return false;
299     }
300     for (const auto& permission : permissions) {
301         if (permission.empty()) {
302             continue;
303         }
304         int32_t result = AccessToken::AccessTokenKit::VerifyAccessToken(dAccessToken, permission);
305         if (result == AccessToken::PermissionState::PERMISSION_DENIED) {
306             HILOGD("dAccessTokenID:%{public}u, permission:%{public}s denied!", dAccessToken, permission.c_str());
307             return false;
308         }
309         HILOGD("dAccessTokenID:%{public}u, permission:%{public}s matched!", dAccessToken, permission.c_str());
310     }
311     return true;
312 }
313 }
314 }