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