1/*
2 * Copyright (c) 2024 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 <pthread.h>
16#include <stdlib.h>
17
18#ifndef APPSPAWN_CLIENT
19#include "appspawn_sandbox.h"
20#endif
21#include "appspawn_client.h"
22#include "appspawn_mount_permission.h"
23#include "appspawn_msg.h"
24#include "appspawn_permission.h"
25#include "appspawn_utils.h"
26#include "json_utils.h"
27#include "securec.h"
28
29typedef struct TagParseJsonContext {
30    SandboxQueue permissionQueue;
31    int32_t maxPermissionIndex;
32    uint32_t inited;
33    AppSpawnClientType type;
34} ParseJsonContext, PermissionManager;
35
36static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
37static PermissionManager g_permissionMgr[CLIENT_MAX] = {};
38
39#ifdef APPSPAWN_SANDBOX_NEW
40static int ParseAppSandboxConfig(const cJSON *root, PermissionManager *mgr)
41{
42    // conditional
43    cJSON *json = cJSON_GetObjectItemCaseSensitive(root, "conditional");
44    APPSPAWN_CHECK(json != NULL, return 0, "No found conditional in config");
45
46    // permission
47    cJSON *config = cJSON_GetObjectItemCaseSensitive(json, "permission");
48    APPSPAWN_CHECK(config != NULL && cJSON_IsArray(config), return 0, "No found permission in config");
49
50    uint32_t configSize = cJSON_GetArraySize(config);
51    for (uint32_t i = 0; i < configSize; i++) {
52        json = cJSON_GetArrayItem(config, i);
53        char *name = GetStringFromJsonObj(json, "name");
54        APPSPAWN_CHECK(name != NULL, break, "No found name in config");
55
56        int ret = AddSandboxPermissionNode(name, &mgr->permissionQueue);
57        APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
58    }
59    return 0;
60}
61
62static PermissionManager *GetPermissionMgrByType(AppSpawnClientType type)
63{
64    APPSPAWN_CHECK_ONLY_EXPER(type < CLIENT_MAX, return NULL);
65    g_permissionMgr[type].type = type;
66    return &g_permissionMgr[type];
67}
68#else
69
70static int ParsePermissionConfig(const cJSON *permissionConfigs, PermissionManager *mgr)
71{
72    cJSON *config = NULL;
73    cJSON_ArrayForEach(config, permissionConfigs)
74    {
75        const char *name = config->string;
76        int ret = AddSandboxPermissionNode(name, &mgr->permissionQueue);
77        APPSPAWN_CHECK_ONLY_EXPER(ret == 0, return ret);
78    }
79    return 0;
80}
81
82static int ParseAppSandboxConfig(const cJSON *appSandboxConfig, PermissionManager *mgr)
83{
84    cJSON *configs = cJSON_GetObjectItemCaseSensitive(appSandboxConfig, "permission");
85    APPSPAWN_CHECK(configs != NULL && cJSON_IsArray(configs), return 0, "No permission in json");
86
87    int ret = 0;
88    uint32_t configSize = (uint32_t)cJSON_GetArraySize(configs);
89    for (uint32_t i = 0; i < configSize; i++) {
90        cJSON *json = cJSON_GetArrayItem(configs, i);
91        ret = ParsePermissionConfig(json, mgr);
92        APPSPAWN_CHECK(ret == 0, return ret, "Parse permission config fail result: %{public}d ", ret);
93    }
94    return ret;
95}
96
97static PermissionManager *GetPermissionMgrByType(AppSpawnClientType type)
98{
99    APPSPAWN_CHECK_ONLY_EXPER(type < CLIENT_MAX, return NULL);
100    g_permissionMgr[0].type = CLIENT_FOR_APPSPAWN;
101    return &g_permissionMgr[0];
102}
103#endif
104
105static int LoadPermissionConfig(PermissionManager *mgr)
106{
107    int ret = ParseJsonConfig("etc/sandbox",
108        mgr->type == CLIENT_FOR_APPSPAWN ? APP_SANDBOX_FILE_NAME : WEB_SANDBOX_FILE_NAME, ParseAppSandboxConfig, mgr);
109    APPSPAWN_CHECK(ret == 0, return ret, "Load sandbox fail %{public}d", ret);
110    mgr->maxPermissionIndex = PermissionRenumber(&mgr->permissionQueue);
111    return 0;
112}
113
114static inline int32_t CheckPermissionManager(PermissionManager *mgr)
115{
116    if (mgr != NULL && mgr->inited) {
117        return 1;
118    }
119    return 0;
120}
121
122static int32_t PMGetPermissionIndex(AppSpawnClientType type, const char *permission)
123{
124    PermissionManager *mgr = GetPermissionMgrByType(type);
125    APPSPAWN_CHECK_ONLY_EXPER(CheckPermissionManager(mgr), return INVALID_PERMISSION_INDEX);
126    return GetPermissionIndexInQueue((SandboxQueue *)&mgr->permissionQueue, permission);
127}
128
129static int32_t PMGetMaxPermissionIndex(AppSpawnClientType type)
130{
131    PermissionManager *mgr = GetPermissionMgrByType(type);
132    APPSPAWN_CHECK_ONLY_EXPER(CheckPermissionManager(mgr), return INVALID_PERMISSION_INDEX);
133    return mgr->maxPermissionIndex;
134}
135
136static const char *PMGetPermissionByIndex(AppSpawnClientType type, int32_t index)
137{
138    PermissionManager *mgr = GetPermissionMgrByType(type);
139    APPSPAWN_CHECK_ONLY_EXPER(CheckPermissionManager(mgr), return NULL);
140    if (mgr->maxPermissionIndex <= index) {
141        return NULL;
142    }
143    const SandboxPermissionNode *node = GetPermissionNodeInQueueByIndex((SandboxQueue *)&mgr->permissionQueue, index);
144    return PERMISSION_NAME(node);
145}
146
147APPSPAWN_STATIC int LoadPermission(AppSpawnClientType type)
148{
149    APPSPAWN_LOGW("LoadPermission %{public}d", type);
150    pthread_mutex_lock(&g_mutex);
151    PermissionManager *mgr = GetPermissionMgrByType(type);
152    if (mgr == NULL) {
153        pthread_mutex_unlock(&g_mutex);
154        return APPSPAWN_ARG_INVALID;
155    }
156
157    if (mgr->inited) {
158        pthread_mutex_unlock(&g_mutex);
159        return 0;
160    }
161    mgr->maxPermissionIndex = -1;
162    mgr->permissionQueue.type = 0;
163    OH_ListInit(&mgr->permissionQueue.front);
164    int ret = LoadPermissionConfig(mgr);
165    if (ret == 0) {
166        mgr->inited = 1;
167    }
168    pthread_mutex_unlock(&g_mutex);
169    return ret;
170}
171
172APPSPAWN_STATIC void DeletePermission(AppSpawnClientType type)
173{
174    pthread_mutex_lock(&g_mutex);
175    PermissionManager *mgr = GetPermissionMgrByType(type);
176    if (mgr == NULL || !mgr->inited) {
177        pthread_mutex_unlock(&g_mutex);
178        return;
179    }
180    DeleteSandboxPermissions(&mgr->permissionQueue);
181    mgr->maxPermissionIndex = -1;
182    mgr->inited = 0;
183    pthread_mutex_unlock(&g_mutex);
184}
185
186int32_t GetPermissionMaxCount()
187{
188    int32_t maxCount = 0;
189    for (uint32_t i = 0; i < CLIENT_MAX; i++) {
190        int32_t max = PMGetMaxPermissionIndex(i);
191        if (max > maxCount) {
192            maxCount = max;
193        }
194    }
195    return maxCount;
196}
197
198int32_t GetPermissionIndex(AppSpawnClientHandle handle, const char *permission)
199{
200    APPSPAWN_CHECK(permission != NULL, return INVALID_PERMISSION_INDEX, "Invalid permission name");
201    if (handle == NULL) {
202        return PMGetPermissionIndex(CLIENT_FOR_APPSPAWN, permission);
203    }
204    AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
205    return PMGetPermissionIndex(reqMgr->type, permission);
206}
207
208int32_t GetMaxPermissionIndex(AppSpawnClientHandle handle)
209{
210    if (handle == NULL) {
211        return PMGetMaxPermissionIndex(CLIENT_FOR_APPSPAWN);
212    }
213    AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
214    return PMGetMaxPermissionIndex(reqMgr->type);
215}
216
217const char *GetPermissionByIndex(AppSpawnClientHandle handle, int32_t index)
218{
219    if (handle == NULL) {
220        return PMGetPermissionByIndex(CLIENT_FOR_APPSPAWN, index);
221    }
222    AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
223    return PMGetPermissionByIndex(reqMgr->type, index);
224}
225
226__attribute__((constructor)) static void LoadPermissionModule(void)
227{
228    (void)LoadPermission(CLIENT_FOR_APPSPAWN);
229    (void)LoadPermission(CLIENT_FOR_NWEBSPAWN);
230}
231
232__attribute__((destructor)) static void DeletePermissionModule(void)
233{
234    DeletePermission(CLIENT_FOR_APPSPAWN);
235    DeletePermission(CLIENT_FOR_NWEBSPAWN);
236}