1 /*
2  * Copyright (c) 2021-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 
16 #include "access_token_open_callback.h"
17 
18 #include "access_token_error.h"
19 #include "access_token.h"
20 #include "accesstoken_log.h"
21 #include "token_field_const.h"
22 
23 namespace OHOS {
24 namespace Security {
25 namespace AccessToken {
26 namespace {
27 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_ACCESSTOKEN, "AccessTokenOpenCallback"};
28 constexpr const char*  INTEGER_STR = " integer not null,";
29 constexpr const char*  TEXT_STR = " text not null,";
30 // back up name is xxx_slave fixed, can not be changed
31 constexpr const char* DATABASE_NAME_BACK = "access_token_slave.db";
32 
33 constexpr const uint32_t FLAG_HANDLE_FROM_ONE_TO_TWO = 1;
34 constexpr const uint32_t FLAG_HANDLE_FROM_TWO_TO_THREE = 1 << 1;
35 constexpr const uint32_t FLAG_HANDLE_FROM_THREE_TO_FOUR = 1 << 2;
36 }
37 
CreateHapTokenInfoTable(NativeRdb::RdbStore & rdbStore)38 int32_t AccessTokenOpenCallback::CreateHapTokenInfoTable(NativeRdb::RdbStore& rdbStore)
39 {
40     std::string tableName;
41     AccessTokenDbUtil::GetTableNameByType(AtmDataType::ACCESSTOKEN_HAP_INFO, tableName);
42 
43     std::string sql = "create table if not exists " + tableName;
44     sql.append(" (")
45         .append(TokenFiledConst::FIELD_TOKEN_ID)
46         .append(INTEGER_STR)
47         .append(TokenFiledConst::FIELD_USER_ID)
48         .append(INTEGER_STR)
49         .append(TokenFiledConst::FIELD_BUNDLE_NAME)
50         .append(TEXT_STR)
51         .append(TokenFiledConst::FIELD_INST_INDEX)
52         .append(INTEGER_STR)
53         .append(TokenFiledConst::FIELD_DLP_TYPE)
54         .append(INTEGER_STR)
55         .append(TokenFiledConst::FIELD_APP_ID)
56         .append(TEXT_STR)
57         .append(TokenFiledConst::FIELD_DEVICE_ID)
58         .append(TEXT_STR)
59         .append(TokenFiledConst::FIELD_APL)
60         .append(INTEGER_STR)
61         .append(TokenFiledConst::FIELD_TOKEN_VERSION)
62         .append(INTEGER_STR)
63         .append(TokenFiledConst::FIELD_TOKEN_ATTR)
64         .append(INTEGER_STR)
65         .append(TokenFiledConst::FIELD_API_VERSION)
66         .append(INTEGER_STR)
67         .append(TokenFiledConst::FIELD_FORBID_PERM_DIALOG)
68         .append(INTEGER_STR)
69         .append("primary key(")
70         .append(TokenFiledConst::FIELD_TOKEN_ID)
71         .append("))");
72 
73     return rdbStore.ExecuteSql(sql);
74 }
75 
CreateNativeTokenInfoTable(NativeRdb::RdbStore & rdbStore)76 int32_t AccessTokenOpenCallback::CreateNativeTokenInfoTable(NativeRdb::RdbStore& rdbStore)
77 {
78     std::string tableName;
79     AccessTokenDbUtil::GetTableNameByType(AtmDataType::ACCESSTOKEN_NATIVE_INFO, tableName);
80 
81     std::string sql = "create table if not exists " + tableName;
82     sql.append(" (")
83         .append(TokenFiledConst::FIELD_TOKEN_ID)
84         .append(INTEGER_STR)
85         .append(TokenFiledConst::FIELD_PROCESS_NAME)
86         .append(TEXT_STR)
87         .append(TokenFiledConst::FIELD_TOKEN_VERSION)
88         .append(INTEGER_STR)
89         .append(TokenFiledConst::FIELD_TOKEN_ATTR)
90         .append(INTEGER_STR)
91         .append(TokenFiledConst::FIELD_DCAP)
92         .append(TEXT_STR)
93         .append(TokenFiledConst::FIELD_NATIVE_ACLS)
94         .append(TEXT_STR)
95         .append(TokenFiledConst::FIELD_APL)
96         .append(INTEGER_STR)
97         .append("primary key(")
98         .append(TokenFiledConst::FIELD_TOKEN_ID)
99         .append("))");
100 
101     return rdbStore.ExecuteSql(sql);
102 }
103 
CreatePermissionDefinitionTable(NativeRdb::RdbStore & rdbStore)104 int32_t AccessTokenOpenCallback::CreatePermissionDefinitionTable(NativeRdb::RdbStore& rdbStore)
105 {
106     std::string tableName;
107     AccessTokenDbUtil::GetTableNameByType(AtmDataType::ACCESSTOKEN_PERMISSION_DEF, tableName);
108 
109     std::string sql = "create table if not exists " + tableName;
110     sql.append(" (")
111         .append(TokenFiledConst::FIELD_TOKEN_ID)
112         .append(INTEGER_STR)
113         .append(TokenFiledConst::FIELD_PERMISSION_NAME)
114         .append(TEXT_STR)
115         .append(TokenFiledConst::FIELD_BUNDLE_NAME)
116         .append(TEXT_STR)
117         .append(TokenFiledConst::FIELD_GRANT_MODE)
118         .append(INTEGER_STR)
119         .append(TokenFiledConst::FIELD_AVAILABLE_LEVEL)
120         .append(INTEGER_STR)
121         .append(TokenFiledConst::FIELD_PROVISION_ENABLE)
122         .append(INTEGER_STR)
123         .append(TokenFiledConst::FIELD_DISTRIBUTED_SCENE_ENABLE)
124         .append(INTEGER_STR)
125         .append(TokenFiledConst::FIELD_LABEL)
126         .append(TEXT_STR)
127         .append(TokenFiledConst::FIELD_LABEL_ID)
128         .append(INTEGER_STR)
129         .append(TokenFiledConst::FIELD_DESCRIPTION)
130         .append(TEXT_STR)
131         .append(TokenFiledConst::FIELD_DESCRIPTION_ID)
132         .append(INTEGER_STR)
133         .append(TokenFiledConst::FIELD_AVAILABLE_TYPE)
134         .append(INTEGER_STR)
135         .append("primary key(")
136         .append(TokenFiledConst::FIELD_TOKEN_ID)
137         .append(",")
138         .append(TokenFiledConst::FIELD_PERMISSION_NAME)
139         .append("))");
140 
141     return rdbStore.ExecuteSql(sql);
142 }
143 
CreatePermissionStateTable(NativeRdb::RdbStore & rdbStore)144 int32_t AccessTokenOpenCallback::CreatePermissionStateTable(NativeRdb::RdbStore& rdbStore)
145 {
146     std::string tableName;
147     AccessTokenDbUtil::GetTableNameByType(AtmDataType::ACCESSTOKEN_PERMISSION_STATE, tableName);
148 
149     std::string sql = "create table if not exists " + tableName;
150     sql.append(" (")
151         .append(TokenFiledConst::FIELD_TOKEN_ID)
152         .append(INTEGER_STR)
153         .append(TokenFiledConst::FIELD_PERMISSION_NAME)
154         .append(TEXT_STR)
155         .append(TokenFiledConst::FIELD_DEVICE_ID)
156         .append(TEXT_STR)
157         .append(TokenFiledConst::FIELD_GRANT_IS_GENERAL)
158         .append(INTEGER_STR)
159         .append(TokenFiledConst::FIELD_GRANT_STATE)
160         .append(INTEGER_STR)
161         .append(TokenFiledConst::FIELD_GRANT_FLAG)
162         .append(INTEGER_STR)
163         .append("primary key(")
164         .append(TokenFiledConst::FIELD_TOKEN_ID)
165         .append(",")
166         .append(TokenFiledConst::FIELD_PERMISSION_NAME)
167         .append(",")
168         .append(TokenFiledConst::FIELD_DEVICE_ID)
169         .append("))");
170 
171     return rdbStore.ExecuteSql(sql);
172 }
173 
CreatePermissionRequestToggleStatusTable(NativeRdb::RdbStore & rdbStore)174 int32_t AccessTokenOpenCallback::CreatePermissionRequestToggleStatusTable(NativeRdb::RdbStore& rdbStore)
175 {
176     std::string tableName;
177     AccessTokenDbUtil::GetTableNameByType(AtmDataType::ACCESSTOKEN_PERMISSION_REQUEST_TOGGLE_STATUS, tableName);
178 
179     std::string sql = "create table if not exists " + tableName;
180     sql.append(" (")
181         .append(TokenFiledConst::FIELD_USER_ID)
182         .append(INTEGER_STR)
183         .append(TokenFiledConst::FIELD_PERMISSION_NAME)
184         .append(TEXT_STR)
185         .append(TokenFiledConst::FIELD_REQUEST_TOGGLE_STATUS)
186         .append(INTEGER_STR)
187         .append("primary key(")
188         .append(TokenFiledConst::FIELD_USER_ID)
189         .append(",")
190         .append(TokenFiledConst::FIELD_PERMISSION_NAME)
191         .append("))");
192 
193     return rdbStore.ExecuteSql(sql);
194 }
195 
OnCreate(NativeRdb::RdbStore & rdbStore)196 int32_t AccessTokenOpenCallback::OnCreate(NativeRdb::RdbStore& rdbStore)
197 {
198     ACCESSTOKEN_LOG_INFO(LABEL, "DB OnCreate.");
199 
200     int32_t res = CreateHapTokenInfoTable(rdbStore);
201     if (res != NativeRdb::E_OK) {
202         ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create table hap_token_info_table.");
203         return res;
204     }
205 
206     res = CreateNativeTokenInfoTable(rdbStore);
207     if (res != NativeRdb::E_OK) {
208         ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create table native_token_info_table.");
209         return res;
210     }
211 
212     res = CreatePermissionDefinitionTable(rdbStore);
213     if (res != NativeRdb::E_OK) {
214         ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create table permission_definition_table.");
215         return res;
216     }
217 
218     res = CreatePermissionStateTable(rdbStore);
219     if (res != NativeRdb::E_OK) {
220         ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create table permission_state_table.");
221         return res;
222     }
223 
224     res = CreatePermissionRequestToggleStatusTable(rdbStore);
225     if (res != NativeRdb::E_OK) {
226         ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create table permission_request_toggle_status_table.");
227         return res;
228     }
229 
230     std::string dbBackPath = std::string(DATABASE_PATH) + std::string(DATABASE_NAME_BACK);
231     if (access(dbBackPath.c_str(), NativeRdb::E_OK) != 0) {
232         return 0;
233     }
234 
235     // if OnCreate solution found back up db, restore from backup, may be origin db has lost
236     ACCESSTOKEN_LOG_WARN(LABEL, "Detech origin database disappear, restore from backup!");
237 
238     res = rdbStore.Restore("");
239     if (res != NativeRdb::E_OK) {
240         ACCESSTOKEN_LOG_ERROR(LABEL, "Db restore failed, res is %{public}d.", res);
241     }
242 
243     ACCESSTOKEN_LOG_WARN(LABEL, "Database restore from backup success!");
244 
245     return 0;
246 }
247 
AddAvailableTypeColumn(NativeRdb::RdbStore & rdbStore)248 int32_t AccessTokenOpenCallback::AddAvailableTypeColumn(NativeRdb::RdbStore& rdbStore)
249 {
250     std::string tableName;
251     AccessTokenDbUtil::GetTableNameByType(AtmDataType::ACCESSTOKEN_PERMISSION_DEF, tableName);
252 
253     // check if column available_type exsit
254     std::string checkSql = "SELECT 1 FROM " + tableName + " WHERE " +
255         TokenFiledConst::FIELD_AVAILABLE_TYPE + "=" + std::to_string(ATokenAvailableTypeEnum::NORMAL);
256 
257     int32_t checkRes = rdbStore.ExecuteSql(checkSql);
258     ACCESSTOKEN_LOG_INFO(LABEL, "Check result is %{public}d.", checkRes);
259     if (checkRes == NativeRdb::E_OK) {
260         // success means there exsit column available_type in table
261         return NativeRdb::E_OK;
262     }
263 
264     // alter table add column
265     std::string sql = "alter table " + tableName + " add column " +
266         TokenFiledConst::FIELD_AVAILABLE_TYPE + " integer default " + std::to_string(ATokenAvailableTypeEnum::NORMAL);
267 
268     int32_t res = rdbStore.ExecuteSql(sql);
269     ACCESSTOKEN_LOG_INFO(LABEL, "Insert column result is %{public}d.", res);
270 
271     return res;
272 }
273 
AddRequestToggleStatusColumn(NativeRdb::RdbStore & rdbStore)274 int32_t AccessTokenOpenCallback::AddRequestToggleStatusColumn(NativeRdb::RdbStore& rdbStore)
275 {
276     std::string tableName;
277     AccessTokenDbUtil::GetTableNameByType(AtmDataType::ACCESSTOKEN_PERMISSION_REQUEST_TOGGLE_STATUS, tableName);
278 
279     // check if column status exsit
280     std::string checkSql = "SELECT 1 FROM " + tableName + " WHERE " +
281         TokenFiledConst::FIELD_REQUEST_TOGGLE_STATUS + "=" + std::to_string(0);
282 
283     int32_t checkRes = rdbStore.ExecuteSql(checkSql);
284     ACCESSTOKEN_LOG_INFO(LABEL, "Check result is %{public}d.", checkRes);
285     if (checkRes == NativeRdb::E_OK) {
286         // success means there exsit column status in table
287         return NativeRdb::E_OK;
288     }
289 
290     // alter table add column
291     std::string sql = "alter table " + tableName + " add column " +
292         TokenFiledConst::FIELD_REQUEST_TOGGLE_STATUS + " integer default " + std::to_string(0); // 0: close
293 
294     int32_t res = rdbStore.ExecuteSql(sql);
295     ACCESSTOKEN_LOG_INFO(LABEL, "Insert column result is %{public}d.", res);
296 
297     return res;
298 }
299 
AddPermDialogCapColumn(NativeRdb::RdbStore & rdbStore)300 int32_t AccessTokenOpenCallback::AddPermDialogCapColumn(NativeRdb::RdbStore& rdbStore)
301 {
302     std::string tableName;
303     AccessTokenDbUtil::GetTableNameByType(AtmDataType::ACCESSTOKEN_HAP_INFO, tableName);
304 
305     // check if column perm_dialog_cap_state exsit
306     std::string checkSql = "SELECT 1 FROM " + tableName + " WHERE " +
307         TokenFiledConst::FIELD_FORBID_PERM_DIALOG + "=" + std::to_string(0);
308 
309     int32_t checkRes = rdbStore.ExecuteSql(checkSql);
310     ACCESSTOKEN_LOG_INFO(LABEL, "Check result is %{public}d.", checkRes);
311     if (checkRes == NativeRdb::E_OK) {
312         // success means there exsit column perm_dialog_cap_state in table
313         return NativeRdb::E_OK;
314     }
315 
316     // alter table add column
317     std::string sql = "alter table " + tableName + " add column " +
318         TokenFiledConst::FIELD_FORBID_PERM_DIALOG + " integer default " + std::to_string(false);
319 
320     int32_t res = rdbStore.ExecuteSql(sql);
321     ACCESSTOKEN_LOG_INFO(LABEL, "Insert column result is %{public}d.", res);
322 
323     return res;
324 }
325 
HandleUpdateWithFlag(NativeRdb::RdbStore & rdbStore,uint32_t flag)326 int32_t AccessTokenOpenCallback::HandleUpdateWithFlag(NativeRdb::RdbStore& rdbStore, uint32_t flag)
327 {
328     int32_t res = NativeRdb::E_OK;
329 
330     if ((flag & FLAG_HANDLE_FROM_ONE_TO_TWO) == FLAG_HANDLE_FROM_ONE_TO_TWO) {
331         res = AddAvailableTypeColumn(rdbStore);
332         if (res != NativeRdb::E_OK) {
333             ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to add column available_type.");
334             return res;
335         }
336 
337         res = AddPermDialogCapColumn(rdbStore);
338         if (res != NativeRdb::E_OK) {
339             ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to add column perm_dialog_cap_state.");
340             return res;
341         }
342     }
343 
344     if ((flag & FLAG_HANDLE_FROM_TWO_TO_THREE) == FLAG_HANDLE_FROM_TWO_TO_THREE) {
345         res = CreatePermissionRequestToggleStatusTable(rdbStore);
346         if (res != NativeRdb::E_OK) {
347             ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to create table permission_request_toggle_status_table.");
348             return res;
349         }
350     }
351 
352     if ((flag & FLAG_HANDLE_FROM_THREE_TO_FOUR) == FLAG_HANDLE_FROM_THREE_TO_FOUR) {
353         res = AddRequestToggleStatusColumn(rdbStore);
354         if (res != NativeRdb::E_OK) {
355             ACCESSTOKEN_LOG_ERROR(LABEL, "Failed to add column status.");
356             return res;
357         }
358     }
359 
360     return res;
361 }
362 
UpdateFromVersionOne(NativeRdb::RdbStore & rdbStore,int32_t targetVersion)363 int32_t AccessTokenOpenCallback::UpdateFromVersionOne(NativeRdb::RdbStore& rdbStore, int32_t targetVersion)
364 {
365     int32_t res = 0;
366     uint32_t flag = 0;
367 
368     switch (targetVersion) {
369         case DATABASE_VERSION_2:
370             flag = FLAG_HANDLE_FROM_ONE_TO_TWO;
371             res = HandleUpdateWithFlag(rdbStore, flag);
372             if (res != NativeRdb::E_OK) {
373                 return res;
374             }
375             break;
376 
377         case DATABASE_VERSION_3:
378             flag = FLAG_HANDLE_FROM_ONE_TO_TWO + FLAG_HANDLE_FROM_TWO_TO_THREE;
379             res = HandleUpdateWithFlag(rdbStore, flag);
380             if (res != NativeRdb::E_OK) {
381                 return res;
382             }
383             break;
384 
385         case DATABASE_VERSION_4:
386             flag = FLAG_HANDLE_FROM_ONE_TO_TWO + FLAG_HANDLE_FROM_TWO_TO_THREE + FLAG_HANDLE_FROM_THREE_TO_FOUR;
387             res = HandleUpdateWithFlag(rdbStore, flag);
388             if (res != NativeRdb::E_OK) {
389                 return res;
390             }
391             break;
392 
393         default:
394             break;
395     }
396 
397     return res;
398 }
399 
UpdateFromVersionTwo(NativeRdb::RdbStore & rdbStore,int32_t targetVersion)400 int32_t AccessTokenOpenCallback::UpdateFromVersionTwo(NativeRdb::RdbStore& rdbStore, int32_t targetVersion)
401 {
402     int32_t res = 0;
403     uint32_t flag = 0;
404 
405     switch (targetVersion) {
406         case DATABASE_VERSION_3:
407             flag = FLAG_HANDLE_FROM_TWO_TO_THREE;
408             res = HandleUpdateWithFlag(rdbStore, flag);
409             if (res != NativeRdb::E_OK) {
410                 return res;
411             }
412             break;
413 
414         case DATABASE_VERSION_4:
415             flag = FLAG_HANDLE_FROM_TWO_TO_THREE + FLAG_HANDLE_FROM_THREE_TO_FOUR;
416             res = HandleUpdateWithFlag(rdbStore, flag);
417             if (res != NativeRdb::E_OK) {
418                 return res;
419             }
420             break;
421 
422         default:
423             break;
424     }
425 
426     return res;
427 }
428 
UpdateFromVersionThree(NativeRdb::RdbStore & rdbStore,int32_t targetVersion)429 int32_t AccessTokenOpenCallback::UpdateFromVersionThree(NativeRdb::RdbStore& rdbStore, int32_t targetVersion)
430 {
431     int32_t res = 0;
432     uint32_t flag = 0;
433 
434     switch (targetVersion) {
435         case DATABASE_VERSION_4:
436             flag = FLAG_HANDLE_FROM_THREE_TO_FOUR;
437             res = HandleUpdateWithFlag(rdbStore, flag);
438             if (res != NativeRdb::E_OK) {
439                 return res;
440             }
441             break;
442 
443         default:
444             break;
445     }
446 
447     return res;
448 }
449 
OnUpgrade(NativeRdb::RdbStore & rdbStore,int32_t currentVersion,int32_t targetVersion)450 int32_t AccessTokenOpenCallback::OnUpgrade(NativeRdb::RdbStore& rdbStore, int32_t currentVersion, int32_t targetVersion)
451 {
452     ACCESSTOKEN_LOG_INFO(LABEL, "DB OnUpgrade from currentVersion %{public}d to targetVersion %{public}d.",
453         currentVersion, targetVersion);
454 
455     int32_t res = 0;
456 
457     switch (currentVersion) {
458         case DATABASE_VERSION_1:
459             res = UpdateFromVersionOne(rdbStore, targetVersion);
460             if (res != 0) {
461                 return res;
462             }
463             break;
464 
465         case DATABASE_VERSION_2:
466             res = UpdateFromVersionTwo(rdbStore, targetVersion);
467             if (res != 0) {
468                 return res;
469             }
470             break;
471 
472         case DATABASE_VERSION_3:
473             res = UpdateFromVersionThree(rdbStore, targetVersion);
474             if (res != 0) {
475                 return res;
476             }
477             break;
478 
479         default:
480             break;
481     }
482 
483     return res;
484 }
485 } // namespace AccessToken
486 } // namespace Security
487 } // namespace OHOS
488