1 /*
2  * Copyright (c) 2024 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 "uri_utils.h"
17 
18 #include "ability_util.h"
19 #include "ability_config.h"
20 #include "ability_manager_errors.h"
21 #include "accesstoken_kit.h"
22 #include "extension_ability_info.h"
23 #include "hilog_tag_wrapper.h"
24 #include "in_process_call_wrapper.h"
25 #include "ipc_skeleton.h"
26 #include "tokenid_kit.h"
27 #include "ui_extension_utils.h"
28 #include "uri_permission_manager_client.h"
29 
30 namespace OHOS {
31 namespace AAFwk {
32 namespace {
33 const std::string PARAMS_URI = "ability.verify.uri";
34 const std::string DISTRIBUTED_FILES_PATH = "/data/storage/el2/distributedfiles/";
35 const int32_t MAX_URI_COUNT = 500;
36 constexpr int32_t API13 = 13;
37 constexpr int32_t API_VERSION_MOD = 100;
38 constexpr uint32_t TOKEN_ID_BIT_SIZE = 32;
39 }
40 
UriUtils()41 UriUtils::UriUtils() {}
42 
~UriUtils()43 UriUtils::~UriUtils() {}
44 
GetInstance()45 UriUtils &UriUtils::GetInstance()
46 {
47     static UriUtils utils;
48     return utils;
49 }
50 
GetUriListFromWantDms(const Want &want)51 std::vector<std::string> UriUtils::GetUriListFromWantDms(const Want &want)
52 {
53     std::vector<std::string> uriVec = want.GetStringArrayParam(PARAMS_URI);
54     TAG_LOGD(AAFwkTag::ABILITYMGR, "uriVec size: %{public}zu", uriVec.size());
55     if (uriVec.size() > MAX_URI_COUNT) {
56         TAG_LOGE(AAFwkTag::ABILITYMGR, "uri list size is more than %{public}u", MAX_URI_COUNT);
57         return {};
58     }
59     std::vector<std::string> validUriVec;
60     for (auto &&str : uriVec) {
61         Uri uri(str);
62         auto &&scheme = uri.GetScheme();
63         TAG_LOGI(AAFwkTag::ABILITYMGR, "uri scheme: %{public}s", scheme.c_str());
64         // only support file scheme
65         if (scheme != "file") {
66             TAG_LOGW(AAFwkTag::ABILITYMGR, "only support file uri");
67             continue;
68         }
69         std::string srcPath = uri.GetPath();
70         if (std::filesystem::exists(srcPath) && std::filesystem::is_symlink(srcPath)) {
71             TAG_LOGE(AAFwkTag::ABILITYMGR, "soft links not allowed");
72             continue;
73         }
74         std::string absolutePath;
75         if (uri.IsRelative()) {
76             char path[PATH_MAX] = {0};
77             if (realpath(srcPath.c_str(), path) == nullptr) {
78                 TAG_LOGE(AAFwkTag::ABILITYMGR, "fail, errno :%{public}d", errno);
79                 continue;
80             }
81             absolutePath = path;
82         } else {
83             absolutePath = srcPath;
84         }
85         if (absolutePath.compare(0, DISTRIBUTED_FILES_PATH.size(), DISTRIBUTED_FILES_PATH) != 0) {
86             TAG_LOGE(AAFwkTag::ABILITYMGR, "uri not distributed path");
87             continue;
88         }
89         validUriVec.emplace_back(str);
90     }
91     TAG_LOGD(AAFwkTag::ABILITYMGR, "size of vaid uri is %{public}zu", validUriVec.size());
92     return validUriVec;
93 }
94 
FilterUriWithPermissionDms(Want &want, uint32_t tokenId)95 void UriUtils::FilterUriWithPermissionDms(Want &want, uint32_t tokenId)
96 {
97     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
98     if ((want.GetFlags() & (Want::FLAG_AUTH_READ_URI_PERMISSION | Want::FLAG_AUTH_WRITE_URI_PERMISSION)) == 0) {
99         TAG_LOGW(AAFwkTag::ABILITYMGR, "flag invalid");
100         return;
101     }
102     auto uriVec = GetUriListFromWantDms(want);
103     TAG_LOGI(AAFwkTag::ABILITYMGR, "uri valid uris size: %{public}zu", uriVec.size());
104     if (uriVec.empty()) {
105         TAG_LOGI(AAFwkTag::ABILITYMGR, "uriVec empty");
106         want.SetParam(PARAMS_URI, uriVec);
107         return;
108     }
109     auto checkResult = IN_PROCESS_CALL(UriPermissionManagerClient::GetInstance().CheckUriAuthorization(
110         uriVec, want.GetFlags(), tokenId));
111     std::vector<std::string> validUriVec;
112     for (size_t i = 0; i < checkResult.size(); i++) {
113         if (checkResult[i]) {
114             validUriVec.emplace_back(uriVec[i]);
115         }
116     }
117     TAG_LOGI(AAFwkTag::ABILITYMGR, "authorized uri size :%{public}zu", validUriVec.size());
118     want.SetParam(PARAMS_URI, validUriVec);
119 }
120 
CheckNonImplicitShareFileUri(const Want &want, int32_t userId, uint32_t specifyTokenId)121 int32_t UriUtils::CheckNonImplicitShareFileUri(const Want &want, int32_t userId, uint32_t specifyTokenId)
122 {
123     auto element = want.GetElement();
124     TAG_LOGD(AAFwkTag::ABILITYMGR, "CheckNonImplicitShareFileUri, %{public}s-%{public}s",
125         element.GetBundleName().c_str(), element.GetAbilityName().c_str());
126     if (element.GetBundleName().empty() || element.GetAbilityName().empty()) {
127         return ERR_OK;
128     }
129     if (!IsGrantUriPermissionFlag(want)) {
130         return ERR_OK;
131     }
132     bool isFileUri = (!want.GetUriString().empty() && want.GetUri().GetScheme() == "file");
133     if (!isFileUri && want.GetStringArrayParam(AbilityConfig::PARAMS_STREAM).empty()) {
134         TAG_LOGD(AAFwkTag::ABILITYMGR, "not file uri");
135         return ERR_OK;
136     }
137     // SA and system app support
138     auto callerTokenId = specifyTokenId > 0 ? specifyTokenId : IPCSkeleton::GetCallingTokenID();
139     return CheckNonImplicitShareFileUriInner(callerTokenId, element.GetBundleName(), userId);
140 }
141 
CheckNonImplicitShareFileUriInner(uint32_t callerTokenId, const std::string &targetBundleName, int32_t userId)142 int32_t UriUtils::CheckNonImplicitShareFileUriInner(uint32_t callerTokenId, const std::string &targetBundleName,
143     int32_t userId)
144 {
145     auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callerTokenId);
146     if (tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE) {
147         TAG_LOGD(AAFwkTag::ABILITYMGR, "SA call");
148         return ERR_OK;
149     }
150     if (tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_HAP) {
151         Security::AccessToken::HapTokenInfo hapInfo;
152         auto ret = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(callerTokenId, hapInfo);
153         if (ret != Security::AccessToken::AccessTokenKitRet::RET_SUCCESS) {
154             TAG_LOGE(AAFwkTag::URIPERMMGR, "GetHapTokenInfo failed, ret:%{public}d", ret);
155             return INNER_ERR;
156         }
157         // check api version
158         TAG_LOGD(AAFwkTag::ABILITYMGR, "CallerBundleName:%{public}s, API:%{public}d",
159             hapInfo.bundleName.c_str(), hapInfo.apiVersion);
160         if ((hapInfo.apiVersion % API_VERSION_MOD) < API13) {
161             TAG_LOGD(AAFwkTag::ABILITYMGR, "api version lower than 13");
162             return ERR_OK;
163         }
164         // check system app
165         uint64_t fullCallerTokenId = (static_cast<uint64_t>(hapInfo.tokenAttr) << TOKEN_ID_BIT_SIZE) + callerTokenId;
166         if (Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullCallerTokenId)) {
167             TAG_LOGD(AAFwkTag::ABILITYMGR, "system app call");
168             return ERR_OK;
169         }
170     }
171     // target is system app
172     if (IsSystemApplication(targetBundleName, userId)) {
173         TAG_LOGD(AAFwkTag::ABILITYMGR, "target is system app");
174         return ERR_OK;
175     }
176     TAG_LOGE(AAFwkTag::ABILITYMGR, "Not allowed to share file uri non-implicitly");
177     return CHECK_PERMISSION_FAILED;
178 }
179 
IsSystemApplication(const std::string &bundleName, int32_t userId)180 bool UriUtils::IsSystemApplication(const std::string &bundleName, int32_t userId)
181 {
182     auto bundleMgrHelper = AbilityUtil::GetBundleManagerHelper();
183     if (!bundleMgrHelper) {
184         TAG_LOGW(AAFwkTag::ABILITYMGR, "GetBundleManagerHelper failed");
185         return false;
186     }
187     AppExecFwk::ApplicationInfo appInfo;
188     if (!IN_PROCESS_CALL(bundleMgrHelper->GetApplicationInfo(bundleName,
189         AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, userId, appInfo))) {
190         TAG_LOGW(AAFwkTag::ABILITYMGR, "GetApplicationInfo failed");
191         return false;
192     }
193     return appInfo.isSystemApp;
194 }
195 
GetPermissionedUriList(const std::vector<std::string> &uriVec, const std::vector<bool> &checkResults, Want &want)196 std::vector<Uri> UriUtils::GetPermissionedUriList(const std::vector<std::string> &uriVec,
197     const std::vector<bool> &checkResults, Want &want)
198 {
199     std::vector<Uri> permissionedUris;
200     if (uriVec.size() != checkResults.size()) {
201         TAG_LOGE(AAFwkTag::ABILITYMGR, "Invalid param: %{public}zu : %{public}zu",
202             uriVec.size(), checkResults.size());
203         return permissionedUris;
204     }
205     // process uri
206     size_t startIndex = 0;
207     if (!want.GetUriString().empty()) {
208         if (checkResults[startIndex]) {
209             permissionedUris.emplace_back(want.GetUri());
210         } else if (want.GetUri().GetScheme() == "file") {
211             // erase uri param
212             want.SetUri("");
213             TAG_LOGI(AAFwkTag::ABILITYMGR, "erase uri param.");
214         }
215         startIndex = 1;
216     }
217     // process param stream
218     std::vector<std::string> paramStreamUris;
219     for (size_t index = startIndex; index < checkResults.size(); index++) {
220         auto uri = Uri(uriVec[index]);
221         if (checkResults[index]) {
222             permissionedUris.emplace_back(uri);
223             paramStreamUris.emplace_back(uriVec[index]);
224         } else if (uri.GetScheme() != "file") {
225             paramStreamUris.emplace_back(uriVec[index]);
226         }
227     }
228     if (paramStreamUris.size() != (checkResults.size() - startIndex)) {
229         // erase old param stream and set new param stream
230         want.RemoveParam(AbilityConfig::PARAMS_STREAM);
231         want.SetParam(AbilityConfig::PARAMS_STREAM, paramStreamUris);
232         TAG_LOGI(AAFwkTag::ABILITYMGR, "startIndex: %{public}zu, uriVec: %{public}zu, paramStreamUris: %{public}zu",
233             startIndex, uriVec.size(), paramStreamUris.size());
234     }
235     return permissionedUris;
236 }
237 
GetUriListFromWant(Want &want, std::vector<std::string> &uriVec)238 bool UriUtils::GetUriListFromWant(Want &want, std::vector<std::string> &uriVec)
239 {
240     auto uriStr = want.GetUri().ToString();
241     uriVec = want.GetStringArrayParam(AbilityConfig::PARAMS_STREAM);
242     if (uriVec.empty() && uriStr.empty()) {
243         TAG_LOGW(AAFwkTag::ABILITYMGR, "uriVec empty.");
244         return false;
245     }
246     // process param stream
247     auto paramStreamUriCount = uriVec.size();
248     if (uriStr.empty() && paramStreamUriCount > MAX_URI_COUNT) {
249         TAG_LOGW(AAFwkTag::ABILITYMGR, "uri empty, paream stream counts: %{public}zu", paramStreamUriCount);
250         uriVec.resize(MAX_URI_COUNT);
251         want.RemoveParam(AbilityConfig::PARAMS_STREAM);
252         want.SetParam(AbilityConfig::PARAMS_STREAM, uriVec);
253     }
254     if (!uriStr.empty() && paramStreamUriCount > MAX_URI_COUNT - 1) {
255         TAG_LOGW(AAFwkTag::ABILITYMGR, "paream stream counts: %{public}zu", paramStreamUriCount);
256         uriVec.resize(MAX_URI_COUNT - 1);
257         want.RemoveParam(AbilityConfig::PARAMS_STREAM);
258         want.SetParam(AbilityConfig::PARAMS_STREAM, uriVec);
259     }
260     // process uri
261     if (!uriStr.empty()) {
262         uriVec.insert(uriVec.begin(), uriStr);
263     }
264     return true;
265 }
266 
IsGrantUriPermissionFlag(const Want &want)267 bool UriUtils::IsGrantUriPermissionFlag(const Want &want)
268 {
269     return ((want.GetFlags() & (Want::FLAG_AUTH_READ_URI_PERMISSION | Want::FLAG_AUTH_WRITE_URI_PERMISSION)) != 0);
270 }
271 
CheckUriPermissionForServiceExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType)272 void UriUtils::CheckUriPermissionForServiceExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType)
273 {
274     TAG_LOGD(AAFwkTag::ABILITYMGR, "CheckUriPermissionForServiceExtension called.");
275     if (extensionAbilityType != AppExecFwk::ExtensionAbilityType::SERVICE &&
276         extensionAbilityType != AppExecFwk::ExtensionAbilityType::UI_SERVICE) {
277         return;
278     }
279     CheckUriPermissionForExtension(want, 0);
280     return;
281 }
282 
CheckUriPermissionForUIExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType, uint32_t tokenId)283 void UriUtils::CheckUriPermissionForUIExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType,
284     uint32_t tokenId)
285 {
286     TAG_LOGD(AAFwkTag::ABILITYMGR, "CheckUriPermissionForUIExtension called.");
287     if (!UIExtensionUtils::IsUIExtension(extensionAbilityType)) {
288         return;
289     }
290     CheckUriPermissionForExtension(want, tokenId);
291     return;
292 }
293 
CheckUriPermissionForExtension(Want &want, uint32_t tokenId)294 void UriUtils::CheckUriPermissionForExtension(Want &want, uint32_t tokenId)
295 {
296     uint32_t flag = want.GetFlags();
297     if (!IsGrantUriPermissionFlag(want)) {
298         TAG_LOGD(AAFwkTag::ABILITYMGR, "No grant uri flag: %{public}u.", flag);
299         return;
300     }
301     std::vector<std::string> uriVec;
302     if (!UriUtils::GetUriListFromWant(want, uriVec)) {
303         TAG_LOGW(AAFwkTag::ABILITYMGR, "No file uri neet grant.");
304         return;
305     }
306     auto callerTokenId = tokenId > 0 ? tokenId : want.GetIntParam(Want::PARAM_RESV_CALLER_TOKEN, 0);
307     // check uri permission
308     auto checkResults = IN_PROCESS_CALL(UriPermissionManagerClient::GetInstance().CheckUriAuthorization(
309         uriVec, flag, callerTokenId));
310     // remove unpermissioned uri from want
311     UriUtils::GetInstance().GetPermissionedUriList(uriVec, checkResults, want);
312     return;
313 }
314 
IsPermissionPreCheckedType(AppExecFwk::ExtensionAbilityType extensionAbilityType)315 bool UriUtils::IsPermissionPreCheckedType(AppExecFwk::ExtensionAbilityType extensionAbilityType)
316 {
317     return extensionAbilityType == AppExecFwk::ExtensionAbilityType::SERVICE ||
318         extensionAbilityType == AppExecFwk::ExtensionAbilityType::UI_SERVICE ||
319         UIExtensionUtils::IsUIExtension(extensionAbilityType);
320 }
321 } // AAFwk
322 } // OHOS
323