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