1 /*
2 * Copyright (c) 2023 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 #include "grant_permissions.h"
16
17 #include <string>
18 #include <vector>
19
20 #include "access_token.h"
21 #include "accesstoken_kit.h"
22 #include "ipc_skeleton.h"
23 #include "js_native_api.h"
24 #include "log.h"
25 #include "n_napi.h"
26 #include "parameter.h"
27 #include "tokenid_kit.h"
28
29 namespace OHOS {
30 namespace AppFileService {
31 namespace ModuleFileShare {
32 using namespace OHOS::FileManagement::LibN;
33 using namespace OHOS::Security::AccessToken;
34 using namespace std;
35
36 namespace {
37 const std::string FILE_ACCESS_PERMISSION = "ohos.permission.FILE_ACCESS_PERSIST";
38 const std::string FULL_MOUNT_ENABLE_PARAMETER = "const.filemanager.full_mount.enable";
39
CheckPermission(const string & permission)40 static bool CheckPermission(const string &permission)
41 {
42 Security::AccessToken::AccessTokenID tokenCaller = IPCSkeleton::GetCallingTokenID();
43 return Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenCaller, permission) ==
44 Security::AccessToken::PermissionState::PERMISSION_GRANTED;
45 }
46
CheckFileManagerFullMountEnable()47 static bool CheckFileManagerFullMountEnable()
48 {
49 char value[] = "false";
50 int retSystem = GetParameter(FULL_MOUNT_ENABLE_PARAMETER.c_str(), "false", value, sizeof(value));
51 if (retSystem > 0 && !strcmp(value, "true")) {
52 LOGE("The full mount enable parameter is true");
53 return true;
54 }
55 LOGD("The full mount enable parameter is false");
56 return false;
57 }
58 } // namespace
59
GetErrData(napi_env env,deque<struct PolicyErrorResult> & errorResults)60 static napi_value GetErrData(napi_env env, deque<struct PolicyErrorResult> &errorResults)
61 {
62 napi_value res = nullptr;
63 napi_status status = napi_create_array(env, &res);
64 if (status != napi_ok) {
65 LOGE("Failed to create array");
66 return nullptr;
67 }
68 size_t index = 0;
69 for (auto &iter : errorResults) {
70 NVal obj = NVal::CreateObject(env);
71 obj.AddProp("uri", NVal::CreateUTF8String(env, iter.uri).val_);
72 obj.AddProp("code", NVal::CreateInt32(env, iter.code).val_);
73 obj.AddProp("message", NVal::CreateUTF8String(env, iter.message).val_);
74 status = napi_set_element(env, res, index++, obj.val_);
75 if (status != napi_ok) {
76 LOGE("Failed to set element on data");
77 return nullptr;
78 }
79 }
80 return res;
81 }
82
GetResultData(napi_env env,const vector<bool> & results)83 static napi_value GetResultData(napi_env env, const vector<bool> &results)
84 {
85 napi_value res = nullptr;
86 napi_status status = napi_create_array(env, &res);
87 if (status != napi_ok) {
88 LOGE("Failed to create array");
89 return nullptr;
90 }
91 size_t index = 0;
92 for (const auto &iter : results) {
93 napi_value value;
94 napi_get_boolean(env, iter, &value);
95 status = napi_set_element(env, res, index++, value);
96 if (status != napi_ok) {
97 LOGE("Failed to set element on data");
98 return nullptr;
99 }
100 }
101 return res;
102 }
103
GetUriPoliciesArg(napi_env env,napi_value agrv,std::vector<UriPolicyInfo> & uriPolicies)104 static napi_status GetUriPoliciesArg(napi_env env, napi_value agrv, std::vector<UriPolicyInfo> &uriPolicies)
105 {
106 uint32_t count;
107 napi_status status = napi_get_array_length(env, agrv, &count);
108 if (status != napi_ok) {
109 LOGE("get array length failed");
110 return status;
111 }
112 if (count > MAX_ARRAY_SIZE) {
113 LOGE("The length of the array is extra-long");
114 return napi_invalid_arg;
115 }
116 for (uint32_t i = 0; i < count; i++) {
117 napi_handle_scope scope;
118 status = napi_open_handle_scope(env, &scope);
119 if (status != napi_ok) {
120 return status;
121 }
122 napi_value object;
123 status = napi_get_element(env, agrv, i, &object);
124 if (status != napi_ok) {
125 LOGE("get element failed");
126 return status;
127 }
128 napi_value uriValue;
129 napi_value modeValue;
130 status = napi_get_named_property(env, object, "uri", &uriValue);
131 if (status != napi_ok) {
132 LOGE("get named property failed");
133 return status;
134 }
135 status = napi_get_named_property(env, object, "operationMode", &modeValue);
136 if (status != napi_ok) {
137 LOGE("get named property failed");
138 return status;
139 }
140 auto [succStr, str, ignore] = NVal(env, uriValue).ToUTF8String();
141 auto [succMode, mode] = NVal(env, modeValue).ToUint32();
142 if (!succStr || !succMode) {
143 LOGE("the argument error");
144 return napi_invalid_arg;
145 }
146 UriPolicyInfo uriPolicy {.uri = str.get(), .mode = mode};
147 uriPolicies.emplace_back(uriPolicy);
148 status = napi_close_handle_scope(env, scope);
149 if (status != napi_ok) {
150 return status;
151 }
152 }
153 return napi_ok;
154 }
155
CheckPathArray(napi_env env,napi_value agrv,uint32_t & count)156 static napi_status CheckPathArray(napi_env env, napi_value agrv, uint32_t &count)
157 {
158 napi_status status = napi_get_array_length(env, agrv, &count);
159 if (status != napi_ok) {
160 LOGE("get array length failed");
161 return status;
162 }
163 if (count == 0 || count > MAX_ARRAY_SIZE) {
164 LOGE("The length of the array is extra-long or length is 0");
165 return napi_invalid_arg;
166 }
167 return napi_ok;
168 }
169
GetPathPoliciesArg(napi_env env,napi_value agrv,std::vector<PathPolicyInfo> & pathPolicies)170 static napi_status GetPathPoliciesArg(napi_env env, napi_value agrv, std::vector<PathPolicyInfo> &pathPolicies)
171 {
172 uint32_t count;
173 napi_status status = CheckPathArray(env, agrv, count);
174 if (status != napi_ok) {
175 return status;
176 }
177 for (uint32_t i = 0; i < count; i++) {
178 napi_handle_scope scope;
179 status = napi_open_handle_scope(env, &scope);
180 if (status != napi_ok) {
181 LOGE("open handle scope failed");
182 return status;
183 }
184 napi_value object;
185 status = napi_get_element(env, agrv, i, &object);
186 if (status != napi_ok) {
187 LOGE("get element failed");
188 return status;
189 }
190 napi_value pathValue;
191 napi_value modeValue;
192 status = napi_get_named_property(env, object, "path", &pathValue);
193 if (status != napi_ok) {
194 LOGE("get named property failed");
195 return status;
196 }
197 status = napi_get_named_property(env, object, "operationMode", &modeValue);
198 if (status != napi_ok) {
199 LOGE("get named property failed");
200 return status;
201 }
202 auto [succStr, str, ignore] = NVal(env, pathValue).ToUTF8String();
203 auto [succMode, mode] = NVal(env, modeValue).ToUint32();
204 if (!succStr || !succMode) {
205 LOGE("the argument error");
206 return napi_invalid_arg;
207 }
208 PathPolicyInfo pathPolicy {.path = str.get(), .mode = mode};
209 pathPolicies.emplace_back(pathPolicy);
210 status = napi_close_handle_scope(env, scope);
211 if (status != napi_ok) {
212 return status;
213 }
214 }
215 return napi_ok;
216 }
217
IsSystemApp()218 static bool IsSystemApp()
219 {
220 uint64_t fullTokenId = OHOS::IPCSkeleton::GetCallingFullTokenID();
221 return TokenIdKit::IsSystemAppByFullTokenID(fullTokenId);
222 }
223
PersistPermission(napi_env env,napi_callback_info info)224 napi_value PersistPermission(napi_env env, napi_callback_info info)
225 {
226 if (!CheckFileManagerFullMountEnable()) {
227 LOGE("The device doesn't support this api");
228 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
229 return nullptr;
230 }
231 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
232 LOGE("PersistPermission has not ohos permission!");
233 NError(E_PERMISSION).ThrowErr(env);
234 return nullptr;
235 }
236 NFuncArg funcArg(env, info);
237 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
238 LOGE("PersistPermission Number of arguments unmatched");
239 NError(E_PARAMS).ThrowErr(env);
240 return nullptr;
241 }
242 std::vector<UriPolicyInfo> uriPolicies;
243 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
244 NError(E_PARAMS).ThrowErr(env);
245 return nullptr;
246 }
247 shared_ptr<PolicyErrorArgs> arg = make_shared<PolicyErrorArgs>();
248 auto cbExec = [uriPolicies, arg]() -> NError {
249 arg->errNo = FilePermission::PersistPermission(uriPolicies, arg->errorResults);
250 return NError(arg->errNo);
251 };
252 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
253 if (err) {
254 if (arg->errNo == EPERM) {
255 napi_value data = err.GetNapiErr(env);
256 napi_set_named_property(env, data, FILEIO_TAG_ERR_DATA.c_str(), GetErrData(env, arg->errorResults));
257 return NVal(env, data);
258 }
259 return {env, err.GetNapiErr(env)};
260 }
261 return NVal::CreateUndefined(env);
262 };
263 const string procedureName = "persist_permission";
264 NVal thisVar(env, funcArg.GetThisVar());
265 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
266 }
267
RevokePermission(napi_env env,napi_callback_info info)268 napi_value RevokePermission(napi_env env, napi_callback_info info)
269 {
270 if (!CheckFileManagerFullMountEnable()) {
271 LOGE("The device doesn't support this api");
272 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
273 return nullptr;
274 }
275 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
276 LOGE("RevokePermission has not ohos permission!");
277 NError(E_PERMISSION).ThrowErr(env);
278 return nullptr;
279 }
280 NFuncArg funcArg(env, info);
281 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
282 LOGE("RevokePermission Number of arguments unmatched");
283 NError(E_PARAMS).ThrowErr(env);
284 return nullptr;
285 }
286 std::vector<UriPolicyInfo> uriPolicies;
287 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
288 NError(E_PARAMS).ThrowErr(env);
289 return nullptr;
290 }
291 shared_ptr<PolicyErrorArgs> arg = make_shared<PolicyErrorArgs>();
292 auto cbExec = [uriPolicies, arg]() -> NError {
293 arg->errNo = FilePermission::RevokePermission(uriPolicies, arg->errorResults);
294 return NError(arg->errNo);
295 };
296 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
297 if (err) {
298 if (arg->errNo == EPERM) {
299 napi_value data = err.GetNapiErr(env);
300 napi_set_named_property(env, data, FILEIO_TAG_ERR_DATA.c_str(), GetErrData(env, arg->errorResults));
301 return NVal(env, data);
302 }
303 return {env, err.GetNapiErr(env)};
304 }
305 return NVal::CreateUndefined(env);
306 };
307 const string procedureName = "revoke_permission";
308 NVal thisVar(env, funcArg.GetThisVar());
309 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
310 }
311
ActivatePermission(napi_env env,napi_callback_info info)312 napi_value ActivatePermission(napi_env env, napi_callback_info info)
313 {
314 if (!CheckFileManagerFullMountEnable()) {
315 LOGE("The device doesn't support this api");
316 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
317 return nullptr;
318 }
319 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
320 LOGE("PersistPermission has not ohos permission!");
321 NError(E_PERMISSION).ThrowErr(env);
322 return nullptr;
323 }
324 NFuncArg funcArg(env, info);
325 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
326 LOGE("ActivatePermission Number of arguments unmatched");
327 NError(E_PARAMS).ThrowErr(env);
328 return nullptr;
329 }
330 std::vector<UriPolicyInfo> uriPolicies;
331 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
332 NError(E_PARAMS).ThrowErr(env);
333 return nullptr;
334 }
335 shared_ptr<PolicyErrorArgs> arg = make_shared<PolicyErrorArgs>();
336 auto cbExec = [uriPolicies, arg]() -> NError {
337 arg->errNo = FilePermission::ActivatePermission(uriPolicies, arg->errorResults);
338 return NError(arg->errNo);
339 };
340 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
341 if (err) {
342 if (arg->errNo == EPERM) {
343 napi_value data = err.GetNapiErr(env);
344 napi_set_named_property(env, data, FILEIO_TAG_ERR_DATA.c_str(), GetErrData(env, arg->errorResults));
345 return NVal(env, data);
346 }
347 return {env, err.GetNapiErr(env)};
348 }
349 return NVal::CreateUndefined(env);
350 };
351 const string procedureName = "activate_permission";
352 NVal thisVar(env, funcArg.GetThisVar());
353 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
354 }
355
DeactivatePermission(napi_env env,napi_callback_info info)356 napi_value DeactivatePermission(napi_env env, napi_callback_info info)
357 {
358 if (!CheckFileManagerFullMountEnable()) {
359 LOGE("The device doesn't support this api");
360 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
361 return nullptr;
362 }
363 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
364 LOGE("PersistPermission has not ohos permission!");
365 NError(E_PERMISSION).ThrowErr(env);
366 return nullptr;
367 }
368 NFuncArg funcArg(env, info);
369 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
370 LOGE("DeactivatePermission Number of arguments unmatched");
371 NError(E_PARAMS).ThrowErr(env);
372 return nullptr;
373 }
374 std::vector<UriPolicyInfo> uriPolicies;
375 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
376 NError(E_PARAMS).ThrowErr(env);
377 return nullptr;
378 }
379 shared_ptr<PolicyErrorArgs> arg = make_shared<PolicyErrorArgs>();
380 auto cbExec = [uriPolicies, arg]() -> NError {
381 arg->errNo = FilePermission::DeactivatePermission(uriPolicies, arg->errorResults);
382 return NError(arg->errNo);
383 };
384 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
385 if (err) {
386 if (arg->errNo == EPERM) {
387 napi_value data = err.GetNapiErr(env);
388 napi_set_named_property(env, data, FILEIO_TAG_ERR_DATA.c_str(), GetErrData(env, arg->errorResults));
389 return NVal(env, data);
390 }
391 return {env, err.GetNapiErr(env)};
392 }
393 return NVal::CreateUndefined(env);
394 };
395 const string procedureName = "deactivate_permission";
396 NVal thisVar(env, funcArg.GetThisVar());
397 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
398 }
399
CheckPersistentPermission(napi_env env,napi_callback_info info)400 napi_value CheckPersistentPermission(napi_env env, napi_callback_info info)
401 {
402 if (!CheckFileManagerFullMountEnable()) {
403 LOGE("The device doesn't support this api");
404 NError(E_DEVICENOTSUPPORT).ThrowErr(env);
405 return nullptr;
406 }
407 if (!CheckPermission(FILE_ACCESS_PERMISSION)) {
408 LOGE("PersistPermission has not ohos permission!");
409 NError(E_PERMISSION).ThrowErr(env);
410 return nullptr;
411 }
412 NFuncArg funcArg(env, info);
413 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
414 LOGE("ActivatePermission Number of arguments unmatched");
415 NError(E_PARAMS).ThrowErr(env);
416 return nullptr;
417 }
418 std::vector<UriPolicyInfo> uriPolicies;
419 if (GetUriPoliciesArg(env, funcArg[NARG_POS::FIRST], uriPolicies) != napi_ok) {
420 NError(E_PARAMS).ThrowErr(env);
421 return nullptr;
422 }
423 shared_ptr<PolicyInfoResultArgs> arg = make_shared<PolicyInfoResultArgs>();
424 auto cbExec = [uriPolicies, arg]() -> NError {
425 arg->errNo = FilePermission::CheckPersistentPermission(uriPolicies, arg->resultData);
426 return NError(arg->errNo);
427 };
428 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
429 if (arg->errNo != 0) {
430 return {env, err.GetNapiErr(env)};
431 }
432 return {env, GetResultData(env, arg->resultData)};
433 };
434 const string procedureName = "check_persist_permission";
435 NVal thisVar(env, funcArg.GetThisVar());
436 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
437 }
438
CheckTokenIdPermission(uint32_t tokenCaller,const string & permission)439 static bool CheckTokenIdPermission(uint32_t tokenCaller, const string &permission)
440 {
441 return AccessTokenKit::VerifyAccessToken(tokenCaller, permission) ==
442 PermissionState::PERMISSION_GRANTED;
443 }
444
CheckArgs(napi_env env,napi_callback_info info,NFuncArg & funcArg)445 static bool CheckArgs(napi_env env, napi_callback_info info, NFuncArg& funcArg)
446 {
447 if (!funcArg.InitArgs(NARG_CNT::THREE)) {
448 LOGE("ActivatePermission Number of arguments unmatched");
449 return false;
450 }
451
452 auto [succTokenId, tokenId] = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
453 if (!succTokenId || tokenId == 0) {
454 LOGE("Failed to get tokenid or tokenid is 0");
455 return false;
456 }
457
458 auto [succPolicyType, policyType] = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32();
459 if (!succPolicyType || policyType < TEMPORARY_TYPE || policyType > PERSISTENT_TYPE) {
460 LOGE("Failed to get policy type or policy type is invalid");
461 return false;
462 }
463 return true;
464 }
465
CheckPathPermission(napi_env env,napi_callback_info info)466 napi_value CheckPathPermission(napi_env env, napi_callback_info info)
467 {
468 if (!IsSystemApp()) {
469 LOGE("FileShare::CheckPathPermission is not System App!");
470 NError(E_PERMISSION_SYS).ThrowErr(env);
471 return nullptr;
472 }
473
474 NFuncArg funcArg(env, info);
475 if (!CheckArgs(env, info, funcArg)) {
476 NError(E_PARAMS).ThrowErr(env);
477 return nullptr;
478 }
479
480 auto [succTokenId, tokenId] = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32();
481
482 uint32_t callerTokenId = OHOS::IPCSkeleton::GetCallingTokenID();
483 if (tokenId != static_cast<int32_t>(callerTokenId)) {
484 if (!CheckTokenIdPermission(callerTokenId, "ohos.permission.CHECK_SANDBOX_POLICY")) {
485 NError(E_PERMISSION).ThrowErr(env);
486 return nullptr;
487 }
488 }
489
490 std::vector<PathPolicyInfo> pathPolicies;
491 if (GetPathPoliciesArg(env, funcArg[NARG_POS::SECOND], pathPolicies) != napi_ok) {
492 NError(E_PARAMS).ThrowErr(env);
493 return nullptr;
494 }
495
496 auto [succPolicyType, policyType] = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32();
497
498 LOGI("check permission target:%{public}d type:%{public}d", tokenId, policyType);
499
500 shared_ptr<PolicyInfoResultArgs> arg = make_shared<PolicyInfoResultArgs>();
501 if (arg == nullptr) {
502 LOGE("PolicyInfoResultArgs make_shared is failed");
503 NError(E_UNKNOWN_ERROR).ThrowErr(env);
504 return nullptr;
505 }
506 auto cbExec = [tokenId { move(tokenId)}, pathPolicies, policyType { move(policyType)}, arg]() -> NError {
507 arg->errNo = FilePermission::CheckPathPermission(tokenId, pathPolicies, policyType, arg->resultData);
508 return NError(arg->errNo);
509 };
510 auto cbCompl = [arg](napi_env env, NError err) -> NVal {
511 if (arg->errNo != 0) {
512 return {env, err.GetNapiErr(env)};
513 }
514 return {env, GetResultData(env, arg->resultData)};
515 };
516 const string procedureName = "check_path_permission";
517 NVal thisVar(env, funcArg.GetThisVar());
518 return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbCompl).val_;
519 }
520
521 } // namespace ModuleFileShare
522 } // namespace AppFileService
523 } // namespace OHOS
524