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_config.h"
19 #include "extension_ability_info.h"
20 #include "hilog_tag_wrapper.h"
21 #include "in_process_call_wrapper.h"
22 #include "ui_extension_utils.h"
23 #include "uri_permission_manager_client.h"
24 
25 namespace OHOS {
26 namespace AAFwk {
27 namespace {
28 const std::string PARAMS_URI = "ability.verify.uri";
29 const std::string DISTRIBUTED_FILES_PATH = "/data/storage/el2/distributedfiles/";
30 const int32_t MAX_URI_COUNT = 500;
31 constexpr int32_t API12 = 12;
32 constexpr int32_t API_VERSION_MOD = 100;
33 }
34 
UriUtils()35 UriUtils::UriUtils() {}
36 
~UriUtils()37 UriUtils::~UriUtils() {}
38 
GetInstance()39 UriUtils &UriUtils::GetInstance()
40 {
41     static UriUtils utils;
42     return utils;
43 }
44 
GetUriListFromWantDms(const Want & want)45 std::vector<std::string> UriUtils::GetUriListFromWantDms(const Want &want)
46 {
47     std::vector<std::string> uriVec = want.GetStringArrayParam(PARAMS_URI);
48     TAG_LOGD(AAFwkTag::ABILITYMGR, "uriVec size: %{public}zu", uriVec.size());
49     if (uriVec.size() > MAX_URI_COUNT) {
50         TAG_LOGE(AAFwkTag::ABILITYMGR, "size of uri list is more than %{public}u", MAX_URI_COUNT);
51         return {};
52     }
53     std::vector<std::string> validUriVec;
54     for (auto &&str : uriVec) {
55         Uri uri(str);
56         auto &&scheme = uri.GetScheme();
57         TAG_LOGI(AAFwkTag::ABILITYMGR, "uri scheme is %{public}s.", scheme.c_str());
58         // only support file scheme
59         if (scheme != "file") {
60             TAG_LOGW(AAFwkTag::ABILITYMGR, "only support file uri.");
61             continue;
62         }
63         std::string srcPath = uri.GetPath();
64         if (std::filesystem::exists(srcPath) && std::filesystem::is_symlink(srcPath)) {
65             TAG_LOGE(AAFwkTag::ABILITYMGR, "soft links are not allowed.");
66             continue;
67         }
68         std::string absolutePath;
69         if (uri.IsRelative()) {
70             char path[PATH_MAX] = {0};
71             if (realpath(srcPath.c_str(), path) == nullptr) {
72                 TAG_LOGE(AAFwkTag::ABILITYMGR, "realpath get failed, errno is %{public}d", errno);
73                 continue;
74             }
75             absolutePath = path;
76         } else {
77             absolutePath = srcPath;
78         }
79         if (absolutePath.compare(0, DISTRIBUTED_FILES_PATH.size(), DISTRIBUTED_FILES_PATH) != 0) {
80             TAG_LOGE(AAFwkTag::ABILITYMGR, "uri is not distributed path");
81             continue;
82         }
83         validUriVec.emplace_back(str);
84     }
85     TAG_LOGD(AAFwkTag::ABILITYMGR, "size of vaid uri is %{public}zu", validUriVec.size());
86     return validUriVec;
87 }
88 
FilterUriWithPermissionDms(Want & want,uint32_t tokenId)89 void UriUtils::FilterUriWithPermissionDms(Want &want, uint32_t tokenId)
90 {
91     TAG_LOGD(AAFwkTag::ABILITYMGR, "called");
92     if ((want.GetFlags() & (Want::FLAG_AUTH_READ_URI_PERMISSION | Want::FLAG_AUTH_WRITE_URI_PERMISSION)) == 0) {
93         TAG_LOGW(AAFwkTag::ABILITYMGR, "Flag is invalid.");
94         return;
95     }
96     auto uriVec = GetUriListFromWantDms(want);
97     TAG_LOGI(AAFwkTag::ABILITYMGR, "size of uri valid uris is %{public}zu", uriVec.size());
98     if (uriVec.empty()) {
99         TAG_LOGI(AAFwkTag::ABILITYMGR, "uriVec is empty.");
100         want.SetParam(PARAMS_URI, uriVec);
101         return;
102     }
103     auto checkResult = IN_PROCESS_CALL(UriPermissionManagerClient::GetInstance().CheckUriAuthorization(
104         uriVec, want.GetFlags(), tokenId));
105     std::vector<std::string> validUriVec;
106     for (size_t i = 0; i < checkResult.size(); i++) {
107         if (checkResult[i]) {
108             validUriVec.emplace_back(uriVec[i]);
109         }
110     }
111     TAG_LOGI(AAFwkTag::ABILITYMGR, "size of authorized uri is %{public}zu", validUriVec.size());
112     want.SetParam(PARAMS_URI, validUriVec);
113 }
114 
CheckNonImplicitShareFileUri(const AbilityRequest & abilityRequest)115 bool UriUtils::CheckNonImplicitShareFileUri(const AbilityRequest &abilityRequest)
116 {
117     if (abilityRequest.appInfo.apiTargetVersion % API_VERSION_MOD <= API12) {
118         return true;
119     }
120     if (abilityRequest.want.GetElement().GetAbilityName().empty()) {
121         return true;
122     }
123     bool isFileUri = !abilityRequest.want.GetUriString().empty() && abilityRequest.want.GetUri().GetScheme() == "file";
124     if (!isFileUri && abilityRequest.want.GetStringArrayParam(AbilityConfig::PARAMS_STREAM).empty()) {
125         return true;
126     }
127     auto flagReadWrite = Want::FLAG_AUTH_READ_URI_PERMISSION | Want::FLAG_AUTH_WRITE_URI_PERMISSION;
128     if ((abilityRequest.want.GetFlags() & flagReadWrite) == 0) {
129         return true;
130     }
131     TAG_LOGE(AAFwkTag::ABILITYMGR, "No permission to share file uri non-implicitly.");
132     return false;
133 }
134 
GetPermissionedUriList(const std::vector<std::string> & uriVec,const std::vector<bool> & checkResults,Want & want)135 std::vector<Uri> UriUtils::GetPermissionedUriList(const std::vector<std::string> &uriVec,
136     const std::vector<bool> &checkResults, Want &want)
137 {
138     std::vector<Uri> permissionedUris;
139     if (uriVec.size() != checkResults.size()) {
140         TAG_LOGE(AAFwkTag::ABILITYMGR, "Invalid param: %{public}zu : %{public}zu",
141             uriVec.size(), checkResults.size());
142         return permissionedUris;
143     }
144     // process uri
145     size_t startIndex = 0;
146     if (!want.GetUriString().empty()) {
147         if (checkResults[startIndex]) {
148             permissionedUris.emplace_back(want.GetUri());
149         } else if (want.GetUri().GetScheme() == "file") {
150             // erase uri param
151             want.SetUri("");
152             TAG_LOGI(AAFwkTag::ABILITYMGR, "erase uri param.");
153         }
154         startIndex = 1;
155     }
156     // process param stream
157     std::vector<std::string> paramStreamUris;
158     for (size_t index = startIndex; index < checkResults.size(); index++) {
159         auto uri = Uri(uriVec[index]);
160         if (checkResults[index]) {
161             permissionedUris.emplace_back(uri);
162             paramStreamUris.emplace_back(uriVec[index]);
163         } else if (uri.GetScheme() != "file") {
164             paramStreamUris.emplace_back(uriVec[index]);
165         }
166     }
167     if (paramStreamUris.size() != (checkResults.size() - startIndex)) {
168         // erase old param stream and set new param stream
169         want.RemoveParam(AbilityConfig::PARAMS_STREAM);
170         want.SetParam(AbilityConfig::PARAMS_STREAM, paramStreamUris);
171         TAG_LOGI(AAFwkTag::ABILITYMGR, "startIndex: %{public}zu, uriVec: %{public}zu, paramStreamUris: %{public}zu",
172             startIndex, uriVec.size(), paramStreamUris.size());
173     }
174     return permissionedUris;
175 }
176 
GetUriListFromWant(Want & want,std::vector<std::string> & uriVec)177 bool UriUtils::GetUriListFromWant(Want &want, std::vector<std::string> &uriVec)
178 {
179     auto uriStr = want.GetUri().ToString();
180     uriVec = want.GetStringArrayParam(AbilityConfig::PARAMS_STREAM);
181     if (uriVec.empty() && uriStr.empty()) {
182         TAG_LOGW(AAFwkTag::ABILITYMGR, "uriVec empty.");
183         return false;
184     }
185     // process param stream
186     auto paramStreamUriCount = uriVec.size();
187     if (uriStr.empty() && paramStreamUriCount > MAX_URI_COUNT) {
188         TAG_LOGW(AAFwkTag::ABILITYMGR, "uri empty, paream stream counts: %{public}zu", paramStreamUriCount);
189         uriVec.resize(MAX_URI_COUNT);
190         want.RemoveParam(AbilityConfig::PARAMS_STREAM);
191         want.SetParam(AbilityConfig::PARAMS_STREAM, uriVec);
192     }
193     if (!uriStr.empty() && paramStreamUriCount > MAX_URI_COUNT - 1) {
194         TAG_LOGW(AAFwkTag::ABILITYMGR, "paream stream counts: %{public}zu", paramStreamUriCount);
195         uriVec.resize(MAX_URI_COUNT - 1);
196         want.RemoveParam(AbilityConfig::PARAMS_STREAM);
197         want.SetParam(AbilityConfig::PARAMS_STREAM, uriVec);
198     }
199     // process uri
200     if (!uriStr.empty()) {
201         uriVec.insert(uriVec.begin(), uriStr);
202     }
203     return true;
204 }
205 
IsGrantUriPermissionFlag(const Want & want)206 bool UriUtils::IsGrantUriPermissionFlag(const Want &want)
207 {
208     return ((want.GetFlags() & (Want::FLAG_AUTH_READ_URI_PERMISSION | Want::FLAG_AUTH_WRITE_URI_PERMISSION)) != 0);
209 }
210 
CheckUriPermissionForServiceExtension(Want & want,AppExecFwk::ExtensionAbilityType extensionAbilityType)211 void UriUtils::CheckUriPermissionForServiceExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType)
212 {
213     TAG_LOGD(AAFwkTag::ABILITYMGR, "CheckUriPermissionForServiceExtension called.");
214     if (extensionAbilityType != AppExecFwk::ExtensionAbilityType::SERVICE) {
215         return;
216     }
217     CheckUriPermissionForExtension(want, 0);
218     return;
219 }
220 
CheckUriPermissionForUIExtension(Want & want,AppExecFwk::ExtensionAbilityType extensionAbilityType,uint32_t tokenId)221 void UriUtils::CheckUriPermissionForUIExtension(Want &want, AppExecFwk::ExtensionAbilityType extensionAbilityType,
222     uint32_t tokenId)
223 {
224     TAG_LOGD(AAFwkTag::ABILITYMGR, "CheckUriPermissionForUIExtension called.");
225     if (!UIExtensionUtils::IsUIExtension(extensionAbilityType)) {
226         return;
227     }
228     CheckUriPermissionForExtension(want, tokenId);
229     return;
230 }
231 
CheckUriPermissionForExtension(Want & want,uint32_t tokenId)232 void UriUtils::CheckUriPermissionForExtension(Want &want, uint32_t tokenId)
233 {
234     uint32_t flag = want.GetFlags();
235     if (!IsGrantUriPermissionFlag(want)) {
236         TAG_LOGD(AAFwkTag::ABILITYMGR, "No grant uri flag: %{public}u.", flag);
237         return;
238     }
239     std::vector<std::string> uriVec;
240     if (!UriUtils::GetUriListFromWant(want, uriVec)) {
241         TAG_LOGW(AAFwkTag::ABILITYMGR, "No file uri neet grant.");
242         return;
243     }
244     auto callerTokenId = tokenId > 0 ? tokenId : want.GetIntParam(Want::PARAM_RESV_CALLER_TOKEN, 0);
245     // check uri permission
246     auto checkResults = IN_PROCESS_CALL(UriPermissionManagerClient::GetInstance().CheckUriAuthorization(
247         uriVec, flag, callerTokenId));
248     // remove unpermissioned uri from want
249     UriUtils::GetInstance().GetPermissionedUriList(uriVec, checkResults, want);
250     return;
251 }
252 
IsPermissionPreCheckedType(AppExecFwk::ExtensionAbilityType extensionAbilityType)253 bool UriUtils::IsPermissionPreCheckedType(AppExecFwk::ExtensionAbilityType extensionAbilityType)
254 {
255     return extensionAbilityType == AppExecFwk::ExtensionAbilityType::SERVICE ||
256         UIExtensionUtils::IsUIExtension(extensionAbilityType);
257 }
258 } // AAFwk
259 } // OHOS