• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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