2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
18 * @author Dongsun Lee (ds73.lee@samsung.com)
20 * @brief DB manager to maintain scanning history
22 #include "db/manager.h"
28 #include "db/statement.h"
29 #include "common/audit/logger.h"
30 #include "common/exception.h"
37 enum SchemaVersion : int {
43 const std::string SCRIPT_CREATE_SCHEMA = "create_schema";
44 const std::string SCRIPT_DROP_ALL_ITEMS = "drop_all";
45 const std::string SCRIPT_MIGRATE = "migrate_";
47 const std::string DB_VERSION_STR = "DB_VERSION";
48 const std::string SCHEMA_INFO_TABLE = "SCHEMA_INFO";
50 RowShPtr extractRow(Statement &stmt)
52 RowShPtr row = std::make_shared<Row>();
54 row->targetName = stmt.getText(); // name.
55 row->fileInAppPath = stmt.getText(); // file_path
56 row->dataVersion = stmt.getText(); // data_version
57 row->malwareName = stmt.getText(); // malware_name
58 row->detailedUrl = stmt.getText(); // detailed_url
59 row->severity = static_cast<csr_cs_severity_level_e>(stmt.getInt()); // severity
60 row->ts = static_cast<time_t>(stmt.getInt64()); // detected_time
61 row->pkgId = stmt.getText(); // pkg_id
62 row->isApp = !row->pkgId.empty();
63 row->isIgnored = static_cast<bool>(stmt.getInt());
68 RowShPtr extractRowCloud(Statement &stmt)
70 RowShPtr row = std::make_shared<Row>();
72 row->targetName = stmt.getText(); // name.
73 row->fileInAppPath.clear();
74 row->dataVersion = stmt.getText(); // data_version
75 row->malwareName = stmt.getText(); // malware_name
76 row->detailedUrl = stmt.getText(); // detailed_url
77 row->severity = static_cast<csr_cs_severity_level_e>(stmt.getInt()); // severity
78 row->ts = static_cast<time_t>(stmt.getInt64()); // detected_time
79 row->pkgId = stmt.getText(); // pkg_id
81 row->isIgnored = static_cast<bool>(stmt.getInt());
86 } // namespace anonymous
88 Manager::Manager(const std::string &dbfile, const std::string &scriptsDir) :
89 m_conn(dbfile, Connection::Create | Connection::ReadWrite |
90 Connection::Serialized),
91 m_scriptsDir(scriptsDir)
93 this->m_conn.exec("PRAGMA foreign_keys = ON;");
95 // run migration if old database is present
96 auto sv = this->getSchemaVersion();
99 case SchemaVersion::LATEST:
100 DEBUG("Database version is latest");
103 case SchemaVersion::NOT_EXIST:
104 INFO("Database initializing!");
105 this->resetDatabase();
109 if (sv < SchemaVersion::NOT_EXIST || sv > SchemaVersion::LATEST) {
110 ERROR("Database corrupted! invalid db version returned! : " << sv);
111 this->resetDatabase();
113 INFO("Database migration! from[" << sv <<
114 "] to[" << SchemaVersion::LATEST << "]");
116 for (int vi = sv; vi < SchemaVersion::LATEST; ++vi)
117 this->m_conn.exec(this->getMigrationScript(vi).c_str());
119 this->setSchemaVersion(SchemaVersion::LATEST);
124 this->m_conn.exec("VACUUM;");
131 void Manager::resetDatabase()
133 this->m_conn.exec(this->getScript(SCRIPT_DROP_ALL_ITEMS).c_str());
134 this->m_conn.exec(this->getScript(SCRIPT_CREATE_SCHEMA).c_str());
135 this->setSchemaVersion(SchemaVersion::LATEST);
138 std::string Manager::getMigrationScript(int sv)
140 return this->getScript(SCRIPT_MIGRATE + std::to_string(sv));
143 std::string Manager::getScript(const std::string &scriptName)
145 auto scriptPath = this->m_scriptsDir + std::string("/") + scriptName + ".sql";
146 std::ifstream is(scriptPath);
149 ThrowExc(CSR_ERROR_DB, "Cannot open script: " << scriptPath);
151 std::istreambuf_iterator<char> begin(is), end;
152 auto str = std::string(begin, end);
155 ThrowExc(CSR_ERROR_DB, "Script file empty: " << scriptPath);
160 bool Manager::isTableExist(const std::string &name)
162 Statement stmt(this->m_conn, Query::CHK_TABLE);
169 int Manager::getSchemaVersion()
171 if (!this->isTableExist(SCHEMA_INFO_TABLE)) {
172 WARN("Schema table doesn't exist. This case would be the first time of "
173 "db manager instantiated in target");
174 return SchemaVersion::NOT_EXIST;
177 Statement stmt(this->m_conn, Query::SEL_SCHEMA_INFO);
179 stmt.bind(DB_VERSION_STR);
181 return stmt.step() ? stmt.getInt() : SchemaVersion::NOT_EXIST;
184 void Manager::setSchemaVersion(int sv)
186 Statement stmt(this->m_conn, Query::INS_SCHEMA_INFO);
188 stmt.bind(DB_VERSION_STR);
191 if (stmt.exec() == 0)
192 ThrowExc(CSR_ERROR_DB, "Failed to set schema version to: " << sv);
195 //===========================================================================
196 // ENGINE_STATE table
197 //===========================================================================
198 csr_state_e Manager::getEngineState(csr_engine_id_e id)
200 std::lock_guard<std::mutex> ll(this->m_mutex);
203 std::lock_guard<std::mutex> l(this->m_stateMutex);
205 if (this->m_stateMap.size() == 0) {
206 Statement stmt(this->m_conn, Query::SEL_ENGINE_STATE_ALL);
208 while (stmt.step()) {
209 auto _id = static_cast<csr_engine_id_e>(stmt.getInt());
210 auto _state = static_cast<csr_state_e>(stmt.getInt());
212 this->m_stateMap[_id] = _state;
216 return (this->m_stateMap.count(id) == 0) ? CSR_STATE_ENABLE : this->m_stateMap[id];
220 void Manager::setEngineState(csr_engine_id_e id, csr_state_e state)
222 std::lock_guard<std::mutex> ll(this->m_mutex);
225 std::lock_guard<std::mutex> l(this->m_stateMutex);
227 Statement stmt(this->m_conn, Query::INS_ENGINE_STATE);
229 stmt.bind(static_cast<int>(id));
230 stmt.bind(static_cast<int>(state));
234 this->m_stateMap[id] = state;
238 //===========================================================================
239 // SCAN_REQUEST table
240 //===========================================================================
242 time_t Manager::getLastScanTime(const std::string &dir, time_t since)
244 std::lock_guard<std::mutex> l(this->m_mutex);
247 std::string current = dir;
248 Statement stmt(this->m_conn, Query::SEL_SCAN_REQUEST);
254 auto candidate = static_cast<time_t>(stmt.getInt64());
255 if ((since < 0 || since < candidate) && latest < candidate)
262 auto pos = current.find_last_of('/');
263 current = (pos == 0) ? "/" : current.substr(0, pos);
271 void Manager::insertLastScanTime(const std::string &dir, const std::string &dataVersion,
274 std::lock_guard<std::mutex> l(this->m_mutex);
276 Statement stmt(this->m_conn, Query::INS_SCAN_REQUEST);
279 stmt.bind(static_cast<sqlite3_int64>(scanTime));
280 stmt.bind(dataVersion);
284 void Manager::deleteLastScanTime(const std::string &dir)
286 std::lock_guard<std::mutex> l(this->m_mutex);
288 Statement stmt(this->m_conn, Query::DEL_SCAN_REQUEST_BY_DIR);
294 void Manager::cleanLastScanTime()
296 std::lock_guard<std::mutex> l(this->m_mutex);
298 Statement stmt(this->m_conn, Query::DEL_SCAN_REQUEST);
303 //===========================================================================
304 // DETECTED_MALWARE_FILE table
305 //===========================================================================
306 RowShPtr Manager::getDetectedByNameOnPath(const std::string &path, time_t since)
308 Statement stmt(this->m_conn, Query::SEL_DETECTED_BY_NAME_ON_PATH);
310 stmt.bind(static_cast<sqlite3_int64>(since));
315 return extractRow(stmt);
318 RowShPtr Manager::getDetectedCloudByNameOnPath(const std::string &path, time_t since)
320 Statement stmt(this->m_conn, Query::SEL_DETECTED_CLOUD_BY_NAME_ON_PATH);
322 stmt.bind(static_cast<sqlite3_int64>(since));
327 return extractRowCloud(stmt);
330 RowShPtr Manager::getDetectedAllByNameOnPath(const std::string &path, time_t since, bool *isByCloud)
332 std::lock_guard<std::mutex> l(this->m_mutex);
333 auto row = this->getDetectedByNameOnPath(path, since);
340 row = this->getDetectedCloudByNameOnPath(path, since);
350 RowShPtrs Manager::getDetectedByNameOnDir(const std::string &dir, time_t since)
352 Statement stmt(this->m_conn, Query::SEL_DETECTED_BY_NAME_ON_DIR);
354 stmt.bind(static_cast<sqlite3_int64>(since));
359 rows.emplace_back(extractRow(stmt));
364 RowShPtrs Manager::getDetectedCloudByNameOnDir(const std::string &dir, time_t since)
366 Statement stmt(this->m_conn, Query::SEL_DETECTED_CLOUD_BY_NAME_ON_DIR);
368 stmt.bind(static_cast<sqlite3_int64>(since));
372 rows.emplace_back(extractRowCloud(stmt));
377 RowShPtrs Manager::getDetectedAllByNameOnDir(const std::string &dir, time_t since)
383 std::lock_guard<std::mutex> l(this->m_mutex);
384 normals = this->getDetectedByNameOnDir(dir, since);
385 clouds = this->getDetectedCloudByNameOnDir(dir, since);
393 for (const auto &cloud : clouds) {
395 auto it = normals.begin();
397 while (it != normals.end()) {
398 if ((*it)->targetName == cloud->targetName) {
399 rows.emplace_back(std::move(*it));
400 it = normals.erase(it);
409 rows.push_back(cloud);
412 for (auto &&normal : normals)
413 rows.emplace_back(std::move(normal));
418 RowShPtrs Manager::getDetectedByFilepathOnDir(const std::string &dir, time_t since)
420 std::lock_guard<std::mutex> l(this->m_mutex);
422 Statement stmt(this->m_conn, Query::SEL_DETECTED_BY_FILEPATH_ON_DIR);
424 stmt.bind(static_cast<sqlite3_int64>(since));
429 rows.emplace_back(extractRow(stmt));
434 RowShPtr Manager::getWorstByPkgPath(const std::string &pkgPath, time_t since)
436 std::lock_guard<std::mutex> l(this->m_mutex);
438 Statement stmt(this->m_conn, Query::SEL_WORST_BY_PKGPATH);
440 stmt.bind(static_cast<sqlite3_int64>(since));
445 RowShPtr row = std::make_shared<Row>();
447 row->targetName = stmt.getText(); // name
448 row->fileInAppPath = stmt.getText(); // file_path
449 row->dataVersion = stmt.getText(); // data_version
450 row->malwareName = stmt.getText(); // malware_name
451 row->detailedUrl = stmt.getText(); // detailed_url
452 row->severity = static_cast<csr_cs_severity_level_e>(stmt.getInt()); // severity
453 row->ts = static_cast<time_t>(stmt.getInt64()); // detected_time
454 row->pkgId = stmt.getText(); // pkg_id
460 void Manager::insertDetectedFile(const CsDetected &d, const std::string &dataVersion)
462 std::lock_guard<std::mutex> l(this->m_mutex);
464 this->insertName(d.targetName);
465 this->insertDetected(d, d.targetName, dataVersion);
468 void Manager::insertDetectedAppByCloud(const std::string &name, const std::string &pkgId,
469 const CsDetected &d, const std::string &dataVersion)
471 std::lock_guard<std::mutex> l(this->m_mutex);
473 this->insertName(name);
474 this->insertDetectedCloud(d, pkgId, name, dataVersion);
477 void Manager::insertCache(const Cache &c)
479 std::lock_guard<std::mutex> l(this->m_mutex);
481 this->insertName(c.pkgPath);
482 for (std::vector<int>::size_type i = 0; i < c.detecteds.size(); ++i)
483 this->insertDetected(*c.detecteds[i], c.filePaths[i], c.dataVersion);
486 void Manager::insertName(const std::string &name)
488 Statement stmt(this->m_conn, Query::INS_NAME);
495 void Manager::insertDetected(const CsDetected &d, const std::string &filepath,
496 const std::string &dataVersion)
498 Statement stmt(this->m_conn, Query::INS_DETECTED);
501 stmt.bind(d.targetName);
502 stmt.bind(dataVersion);
503 stmt.bind(d.malwareName);
504 stmt.bind(d.detailedUrl);
505 stmt.bind(static_cast<int>(d.severity));
506 stmt.bind(static_cast<sqlite3_int64>(d.ts));
510 void Manager::insertDetectedCloud(const CsDetected &d, const std::string &pkgId,
511 const std::string &name, const std::string &dataVersion)
513 Statement stmt(this->m_conn, Query::INS_DETECTED_CLOUD);
517 stmt.bind(dataVersion);
518 stmt.bind(d.malwareName);
519 stmt.bind(d.detailedUrl);
520 stmt.bind(static_cast<int>(d.severity));
521 stmt.bind(static_cast<sqlite3_int64>(d.ts));
525 void Manager::insertWorst(const std::string &pkgId, const std::string &name,
526 const std::string &filepath)
528 std::lock_guard<std::mutex> l(this->m_mutex);
530 Statement stmt(this->m_conn, Query::INS_WORST);
538 void Manager::updateIgnoreFlag(const std::string &name, bool flag)
540 std::lock_guard<std::mutex> l(this->m_mutex);
542 Statement stmt(this->m_conn, Query::UPD_IGNORE);
544 stmt.bind((flag ? 1 : 0));
549 void Manager::deleteDetectedByNameOnPath(const std::string &path)
551 std::lock_guard<std::mutex> l(this->m_mutex);
553 Statement stmt(this->m_conn, Query::DEL_DETECTED_BY_NAME_ON_PATH);
559 void Manager::deleteDetectedByFilepathOnPath(const std::string &path)
561 std::lock_guard<std::mutex> l(this->m_mutex);
563 Statement stmt(this->m_conn, Query::DEL_DETECTED_BY_FILEPATH_ON_PATH);
569 void Manager::deleteDetectedDeprecated(time_t since)
571 std::lock_guard<std::mutex> l(this->m_mutex);
573 Statement stmt(this->m_conn, Query::DEL_DETECTED_DEPRECATED);
575 stmt.bind(static_cast<sqlite3_int64>(since));
578 Statement stmt2(this->m_conn, Query::DEL_DETECTED_DEPRECATED_CLOUD);
580 stmt2.bind(static_cast<sqlite3_int64>(since));
584 void Manager::transactionBegin()
586 this->m_conn.transactionBegin();
589 void Manager::transactionEnd()
591 this->m_conn.transactionEnd();