* Copyright (c) 2024-2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "file_permission_manager.h"
#include <dlfcn.h>
#include <strings.h>
#include "accesstoken_kit.h"
#include "file_uri.h"
#include "hilog_tag_wrapper.h"
#include "ipc_skeleton.h"
#include "permission_constants.h"
#include "permission_verification.h"
#include "tokenid_kit.h"
#include "uri.h"
namespace OHOS {
namespace AAFwk {
namespace {
constexpr int32_t PERMISSION_GRANTED = 1;
constexpr int32_t PERMISSION_DENIED = 2;
constexpr const char* URI_CHECK_SO_NAME = "libams_broker_ext.z.so";
constexpr const char* URI_CHECK_FUNC_NAME = "CheckCollaboratorUriPermission";
bool StartsWithIgnoreCase(const std::string &path, const std::string &prefix)
{
return path.size() >= prefix.size() &&
strncasecmp(path.c_str(), prefix.c_str(), prefix.size()) == 0;
}
}
const std::string FILE_MANAGER_AUTHORITY = "docs";
const std::string STORAGE_URI = "/storage";
const std::string APPDATA_URI = "/storage/Users/currentUser/appdata/";
const std::string DOWNLOAD_PATH = "/storage/Users/currentUser/Download";
const std::string DESKTOP_PATH = "/storage/Users/currentUser/Desktop";
const std::string DOCUMENTS_PATH = "/storage/Users/currentUser/Documents";
const std::string CURRENTUSER = "currentUser";
const std::string BACKFLASH = "/";
DllWrapper::~DllWrapper()
{
if (handle_ != nullptr) {
dlclose(handle_);
}
func_ = nullptr;
}
bool DllWrapper::InitDlSymbol(const char* name, const char* funcName)
{
std::lock_guard<std::mutex> lock(funcLock_);
if (func_ != nullptr) {
TAG_LOGD(AAFwkTag::URIPERMMGR, "func is valid.");
return true;
}
if (handle_ == nullptr) {
if (name == nullptr) {
TAG_LOGE(AAFwkTag::URIPERMMGR, "dlopen failed: name is nullptr");
return false;
}
handle_ = dlopen(name, RTLD_NOW);
if (handle_ == nullptr) {
TAG_LOGE(AAFwkTag::URIPERMMGR, "dlopen failed %{public}s, %{public}s", name, dlerror());
return false;
}
}
func_ = reinterpret_cast<CheckUriFunc>(dlsym(handle_, funcName));
if (func_ == nullptr) {
TAG_LOGE(AAFwkTag::URIPERMMGR, "dlsym failed %{public}s, %{public}s", funcName, dlerror());
dlclose(handle_);
handle_ = nullptr;
return false;
}
return true;
}
CheckUriFunc DllWrapper::GetFunc()
{
std::lock_guard<std::mutex> lock(funcLock_);
return func_;
}
DllWrapper& FilePermissionManager::GetDllWrapper()
{
static DllWrapper dll;
return dll;
}
bool FilePermissionManager::CheckDocsUriPermission(TokenIdPermission &tokenPermission, const std::string &path)
{
if (StartsWithIgnoreCase(path, APPDATA_URI)) {
return tokenPermission.VerifySandboxAccessPermission();
}
auto& dll = GetDllWrapper();
CheckUriFunc func = dll.GetFunc();
if (func != nullptr) {
int32_t ret = func(path, tokenPermission.GetTokenId());
if (ret == PERMISSION_GRANTED) {
return true;
}
if (ret == PERMISSION_DENIED) {
return false;
}
}
if (path.find(STORAGE_URI) == 0) {
return tokenPermission.VerifyFileAccessManagerPermission();
}
return false;
}
static bool CheckFileManagerUriPermission(TokenIdPermission &tokenPermission,
const std::string &filePath,
const std::string &bundleName)
{
std::string path = filePath;
if (path.find(DOWNLOAD_PATH) == 0) {
path = path.substr(DOWNLOAD_PATH.size());
if (path.find(BACKFLASH) == 0) {
path = path.substr(1);
}
std::string dirname = "";
if (path.find(BACKFLASH) != std::string::npos) {
size_t pos = path.find(BACKFLASH);
dirname = path.substr(0, pos);
} else {
dirname = path;
}
if (dirname == bundleName) {
return true;
}
return tokenPermission.VerifyRWDownloadPermission();
}
if (path.find(DESKTOP_PATH) == 0) {
return tokenPermission.VerifyRWDeskTopPermission();
}
if (path.find(DOCUMENTS_PATH) == 0) {
return tokenPermission.VerifyRWDocumentsPermission();
}
return false;
}
PolicyInfo FilePermissionManager::GetPathPolicyInfoFromUri(Uri &uri, uint32_t flag, const std::string &bundleName)
{
AppFileService::ModuleFileUri::FileUri fileUri(uri.ToString());
std::string path = fileUri.GetRealPathBySA(bundleName);
PolicyInfo policyInfo;
policyInfo.path = path;
policyInfo.mode = (flag & (OperationMode::READ_MODE | OperationMode::WRITE_MODE));
return policyInfo;
}
std::vector<bool> FilePermissionManager::CheckUriPersistentPermission(std::vector<Uri> &uriVec,
uint32_t callerTokenId, uint32_t flag, const std::string &bundleName, std::vector<PolicyInfo> &pathPolicies)
{
TAG_LOGI(AAFwkTag::URIPERMMGR,
"CheckUriPersistentPermission call, size of uri is %{public}zu", uriVec.size());
std::vector<bool> resultCodes(uriVec.size(), false);
pathPolicies.clear();
std::vector<int32_t> resultIndex;
std::vector<PolicyInfo> persistPolicys;
TokenIdPermission tokenPermission(callerTokenId);
auto& dll = GetDllWrapper();
(void)dll.InitDlSymbol(URI_CHECK_SO_NAME, URI_CHECK_FUNC_NAME);
for (size_t i = 0; i < uriVec.size(); i++) {
PolicyInfo policyInfo = GetPathPolicyInfoFromUri(uriVec[i], flag);
pathPolicies.emplace_back(policyInfo);
if ((uriVec[i].GetAuthority() == FILE_MANAGER_AUTHORITY) &&
(CheckFileManagerUriPermission(tokenPermission, policyInfo.path, bundleName) ||
CheckDocsUriPermission(tokenPermission, policyInfo.path))) {
resultCodes[i] = true;
continue;
}
resultIndex.emplace_back(i);
persistPolicys.emplace_back(policyInfo);
}
#ifdef ABILITY_RUNTIME_FEATURE_SANDBOXMANAGER
if (persistPolicys.empty()) {
return resultCodes;
}
std::vector<bool> persistResultCodes;
int32_t ret = SandboxManagerKit::CheckPersistPolicy(callerTokenId, persistPolicys, persistResultCodes);
if (ret == 0 && persistResultCodes.size() == resultIndex.size()) {
for (size_t i = 0; i < persistResultCodes.size(); i++) {
auto index = resultIndex[i];
resultCodes[index] = persistResultCodes[i];
}
}
#endif
return resultCodes;
}
}
}