tizen 2.4 release
[framework/security/key-manager.git] / src / manager / service / db-crypto.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file        db-crypto.cpp
18  * @author      Zofia Abramowska (z.abramowska@samsung.com)
19  * @version     1.0
20  * @brief       Implementation of encrypted db access layer
21  */
22
23 #include <fstream>
24 #include <db-crypto.h>
25 #include <dpl/db/sql_connection.h>
26 #include <dpl/log/log.h>
27 #include <ckm/ckm-error.h>
28
29 #pragma GCC diagnostic push
30 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
31
32 namespace {
33     const CKM::PermissionMask DEFAULT_PERMISSIONS =
34                         static_cast<CKM::PermissionMask>(CKM::Permission::READ | CKM::Permission::REMOVE);
35
36     const char *SCRIPTS_PATH = "/usr/share/ckm/scripts/";
37
38     enum DBVersion : int {
39         DB_VERSION_1                   = 1,
40         DB_VERSION_2                   = 2,
41         /* ... since version 3, there is no need to manually
42          * recognize database version.
43          * Remember only that if doing changes to the database,
44          * increment and update DB_VERSION_CURRENT,
45          * then provide migration mechanism!
46          */
47         DB_VERSION_CURRENT             = 3
48     };
49
50     const char *SCRIPT_CREATE_SCHEMA                = "create_schema";
51     const char *SCRIPT_DROP_ALL_ITEMS               = "drop_all";
52     const char *SCRIPT_MIGRATE                      = "migrate_";
53
54     // common substitutions:
55     // 100 - idx
56     // 101 - name
57     // 102 - label
58     // 103 - value
59     // 104 - permissionLabel
60     // 105 - permissionMask
61     const char *DB_CMD_SCHEMA_SET =
62             "REPLACE INTO SCHEMA_INFO(name, value) "
63             "   VALUES(?101, ?103);";
64
65     const char *DB_CMD_SCHEMA_GET =
66             "SELECT * FROM SCHEMA_INFO WHERE name IS ?101;";
67
68     const char *DB_SCHEMA_VERSION_FIELD = "schema_version";
69
70
71     const char *DB_CMD_NAME_INSERT =
72             "INSERT INTO NAMES("
73             "   name, label) "
74             "   VALUES(?101, ?102);";
75
76     const char *DB_CMD_NAME_COUNT_ROWS =
77             "SELECT COUNT(idx) FROM NAMES WHERE name IS ?101 AND label IS ?102;";
78
79     const char *DB_CMD_NAME_DELETE =
80             "DELETE FROM NAMES WHERE name IS ?101 AND label IS ?102;";
81
82     const char *DB_CMD_NAME_DELETE_BY_LABEL =
83             "DELETE FROM NAMES WHERE label IS ?102;";
84
85
86     const char *DB_CMD_OBJECT_INSERT =
87             "INSERT INTO OBJECTS("
88             "   exportable, dataType,"
89             "   algorithmType, encryptionScheme,"
90             "   iv, dataSize, data, tag, idx) "
91             "   VALUES(?001, ?002, ?003, ?004, ?005, "
92             "          ?006, ?007, ?008,"
93             "          (SELECT idx FROM NAMES WHERE name IS ?101 and label IS ?102)"
94             "         );";
95
96     const char *DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL =
97             "SELECT * FROM [join_name_object_tables] "
98             " WHERE (dataType BETWEEN ?001 AND ?002) "
99             " AND name IS ?101 and label IS ?102;";
100
101
102     const char *DB_CMD_KEY_INSERT =
103             "INSERT INTO KEYS(label, key) VALUES (?, ?);";
104     const char *DB_CMD_KEY_SELECT =
105             "SELECT key FROM KEYS WHERE label IS ?;";
106     const char *DB_CMD_KEY_DELETE =
107             "DELETE FROM KEYS WHERE label IS ?;";
108
109
110     const char *DB_CMD_PERMISSION_SET = // SQLite does not support updating views
111             "REPLACE INTO PERMISSIONS(permissionLabel, permissionMask, idx) "
112             " VALUES (?104, ?105, (SELECT idx FROM NAMES WHERE name IS ?101 and label IS ?102));";
113
114     const char *DB_CMD_PERMISSION_SELECT =
115             "SELECT permissionMask FROM [join_name_permission_tables] "
116             " WHERE permissionLabel IS ?104 "
117             " AND name IS ?101 AND label IS ?102;";
118
119     const char *DB_CMD_PERMISSION_DELETE = // SQLite does not support updating views
120             "DELETE FROM PERMISSIONS WHERE permissionLabel IS ?104 AND "
121             " idx IS (SELECT idx FROM NAMES WHERE name IS ?101 AND label IS ?102);";
122
123
124     /*
125      * GROUP BY is necessary because of the following case:
126      * -There are several permissions to L1, N1 (label, name) from other accessors. When listing
127      *  objects accessible by L1 the query will produce one result (L1, N1) for each allowed
128      *  accessor but GROUP BY will reduce them to one so L1 will have (L1, N1) on its list only once
129      */
130     const char *DB_CMD_NAME_SELECT_BY_TYPE_AND_PERMISSION =
131             "SELECT label, name FROM [join_all_tables] "
132             " WHERE (dataType BETWEEN ?001 AND ?002) "
133             " AND permissionLabel IS ?104 AND permissionMask&?004 IS NOT 0 GROUP BY idx;";
134 }
135
136 namespace CKM {
137 namespace DB {
138     Crypto::Crypto(const std::string& path, const RawBuffer &rawPass)
139     {
140         m_connection = NULL;
141         m_inUserTransaction = false;
142         Try {
143             m_connection = new SqlConnection(path, SqlConnection::Flag::Option::CRW);
144             m_connection->SetKey(rawPass);
145             initDatabase();
146             m_connection->ExecCommand("VACUUM;");
147         } Catch(SqlConnection::Exception::ConnectionBroken) {
148             LogError("Couldn't connect to database: " << path);
149             ReThrow(Crypto::Exception::InternalError);
150         } Catch(SqlConnection::Exception::InvalidArguments) {
151             LogError("Couldn't set the key for database");
152             ReThrow(Crypto::Exception::InternalError);
153         } Catch(SqlConnection::Exception::SyntaxError) {
154             LogError("Couldn't initiate the database");
155             ReThrow(Crypto::Exception::InternalError);
156         } Catch(SqlConnection::Exception::InternalError) {
157             LogError("Couldn't create the database");
158             ReThrow(Crypto::Exception::InternalError);
159         }
160     }
161
162     Crypto::Crypto(Crypto &&other) :
163             m_connection(other.m_connection),
164             m_inUserTransaction(other.m_inUserTransaction)
165     {
166         other.m_connection = NULL;
167         other.m_inUserTransaction = false;
168     }
169
170     Crypto::~Crypto() {
171         delete m_connection;
172     }
173
174     Crypto& Crypto::operator=(Crypto&& other) {
175         if (this == &other)
176             return *this;
177         delete m_connection;
178
179         m_connection = other.m_connection;
180         other.m_connection = NULL;
181
182         m_inUserTransaction = other.m_inUserTransaction;
183         other.m_inUserTransaction = false;
184
185         return *this;
186     }
187
188     void Crypto::createTable(
189             const char* create_cmd,
190             const char *table_name)
191     {
192         Try {
193             m_connection->ExecCommand(create_cmd);
194         } Catch(SqlConnection::Exception::SyntaxError) {
195             LogError("Couldn't create table : " << table_name << "!");
196             throw;
197         } Catch(SqlConnection::Exception::InternalError) {
198             LogError("Sqlite got into infinite busy state");
199             throw;
200         }
201     }
202
203     void Crypto::createView(
204             const char* create_cmd)
205     {
206         Try {
207             m_connection->ExecCommand(create_cmd);
208         } Catch(SqlConnection::Exception::SyntaxError) {
209             LogError("Couldn't create view!");
210             throw;
211         } Catch(SqlConnection::Exception::InternalError) {
212             LogError("Sqlite got into infinite busy state");
213             throw;
214         }
215     }
216
217     bool Crypto::getDBVersion(int & schemaVersion)
218     {
219         SchemaInfo SchemaInfo(this);
220
221         /*
222          *  SCHEMA_INFO (o)
223          *  SCHEMA_INFO exists from schema version 3
224          */
225         if (m_connection->CheckTableExist("SCHEMA_INFO")
226            && SchemaInfo.getVersionInfo(schemaVersion)) {
227             LogDebug("Current DB version: " << schemaVersion);
228             return true;
229         }
230
231         /*
232          *  SCHEMA_INFO (x) / CKM_TABLE (o)
233          *  CKM_TABLE exists only in schema version 1
234          *  -> schema version 1
235          */
236         if (m_connection->CheckTableExist("CKM_TABLE")) {
237             schemaVersion = DB_VERSION_1;
238             return true;
239         }
240
241         /*
242          *  SCHEMA_INFO (x) / CKM_TABLE (x) / NAME_TABLE (o)
243          *  NAME_TABLE exists only in schema version 2
244          *  -> schema version 2
245          */
246         if (m_connection->CheckTableExist("NAME_TABLE")) {
247             schemaVersion = DB_VERSION_2;
248             return true;
249         }
250
251         // not recognized - proceed with an empty DBs
252         return false;
253     }
254
255     void Crypto::initDatabase()
256     {
257         // run migration if old database is present
258         int schemaVersion;
259         if( getDBVersion(schemaVersion)==false ||       // DB empty or corrupted
260             schemaVersion > DB_VERSION_CURRENT)         // or too new scheme
261         {
262             LogDebug("no database or database corrupted, initializing the DB");
263             resetDB();
264         }
265         else
266         {
267             // migration needed
268             LogDebug("DB migration from version " << schemaVersion << " to version " << DB_VERSION_CURRENT << " started.");
269             Transaction transaction(this);
270             for(int vi=schemaVersion; vi<DB_VERSION_CURRENT; vi++)
271             {
272                 ScriptOptional script = getMigrationScript(vi);
273                 if(!script)
274                 {
275                     LogError("Error, script to migrate database from version: " << vi <<
276                              " to version: " << vi+1 << " not available, resetting the DB");
277                     resetDB();
278                     break;
279                 }
280
281                 LogInfo("migrating from version " << vi << " to version " << vi+1);
282                 m_connection->ExecCommand((*script).c_str());
283             }
284             // update DB version info
285             SchemaInfo SchemaInfo(this);
286             SchemaInfo.setVersionInfo();
287             transaction.commit();
288         }
289     }
290
291     Crypto::ScriptOptional Crypto::getScript(const std::string &scriptName) const
292     {
293         std::string scriptPath = SCRIPTS_PATH + scriptName + std::string(".sql");
294         std::ifstream is(scriptPath);
295         if(is.fail()) {
296             LogError("Script " << scriptPath << " not found!");
297             return ScriptOptional();
298         }
299
300         std::istreambuf_iterator<char> begin(is),end;
301         return ScriptOptional(std::string(begin, end));
302     }
303
304     Crypto::ScriptOptional Crypto::getMigrationScript(int db_version) const
305     {
306         std::string scriptPath = std::string(SCRIPT_MIGRATE) + std::to_string(db_version);
307         return getScript(scriptPath);
308     }
309
310     void Crypto::createDBSchema() {
311         Transaction transaction(this);
312
313         ScriptOptional script = getScript(SCRIPT_CREATE_SCHEMA);
314         if(!script)
315         {
316             std::string errmsg = "Can not create the database schema: no initialization script";
317             LogError(errmsg);
318             ThrowMsg(Exception::InternalError, errmsg);
319         }
320
321         m_connection->ExecCommand((*script).c_str());
322         SchemaInfo SchemaInfo(this);
323         SchemaInfo.setVersionInfo();
324         transaction.commit();
325     }
326
327     void Crypto::resetDB() {
328         Transaction transaction(this);
329         ScriptOptional script = getScript(SCRIPT_DROP_ALL_ITEMS);
330         if(!script)
331         {
332             std::string errmsg = "Can not clear the database: no clearing script";
333             LogError(errmsg);
334             ThrowMsg(Exception::InternalError, errmsg);
335         }
336
337         m_connection->ExecCommand((*script).c_str());
338         createDBSchema();
339         transaction.commit();
340     }
341
342     bool Crypto::isNameLabelPresent(const Name &name, const Label &owner) const {
343         Try {
344             NameTable nameTable(this->m_connection);
345             return nameTable.isPresent(name, owner);
346         } Catch(SqlConnection::Exception::SyntaxError) {
347             LogError("Couldn't prepare insert statement");
348         } Catch(SqlConnection::Exception::InternalError) {
349             LogError("Couldn't execute insert statement");
350         }
351         ThrowMsg(Crypto::Exception::InternalError,
352                 "Couldn't check if name and label pair is present");
353     }
354
355     void Crypto::saveRows(const Name &name, const Label &owner, const RowVector &rows)
356     {
357         Try {
358             // transaction is present in the layer above
359             NameTable nameTable(this->m_connection);
360             ObjectTable objectTable(this->m_connection);
361             PermissionTable permissionTable(this->m_connection);
362             nameTable.addRow(name, owner);
363             for (const auto &i: rows)
364                 objectTable.addRow(i);
365             permissionTable.setPermission(name,
366                                           owner,
367                                           owner,
368                                           static_cast<int>(DEFAULT_PERMISSIONS));
369             return;
370         } Catch(SqlConnection::Exception::SyntaxError) {
371             LogError("Couldn't prepare insert statement");
372         } Catch(SqlConnection::Exception::InternalError) {
373             LogError("Couldn't execute insert statement: " << _rethrown_exception.GetMessage());
374         }
375         ThrowMsg(Crypto::Exception::InternalError,
376                 "Couldn't save Row");
377     }
378
379     void Crypto::saveRow(const Row &row) {
380         Try {
381             // transaction is present in the layer above
382             NameTable nameTable(this->m_connection);
383             ObjectTable objectTable(this->m_connection);
384             PermissionTable permissionTable(this->m_connection);
385             nameTable.addRow(row.name, row.ownerLabel);
386             objectTable.addRow(row);
387             permissionTable.setPermission(row.name,
388                                           row.ownerLabel,
389                                           row.ownerLabel,
390                                           static_cast<int>(DEFAULT_PERMISSIONS));
391             return;
392         } Catch(SqlConnection::Exception::SyntaxError) {
393             LogError("Couldn't prepare insert statement");
394         } Catch(SqlConnection::Exception::InternalError) {
395             LogError("Couldn't execute insert statement");
396         }
397         ThrowMsg(Crypto::Exception::InternalError,
398                 "Couldn't save Row");
399     }
400
401     bool Crypto::deleteRow(
402             const Name &name,
403             const Label &ownerLabel)
404     {
405         Try {
406             // transaction is present in the layer above
407             NameTable nameTable(this->m_connection);
408             if(nameTable.isPresent(name, ownerLabel))
409             {
410                 nameTable.deleteRow(name, ownerLabel);
411                 return true;
412             }
413             return false;
414         } Catch (SqlConnection::Exception::SyntaxError) {
415             LogError("Couldn't prepare delete statement");
416         } Catch (SqlConnection::Exception::InternalError) {
417             LogError("Couldn't execute delete statement");
418         }
419         ThrowMsg(Crypto::Exception::InternalError,
420                 "Couldn't delete Row for name " << name << " using ownerLabel " << ownerLabel);
421     }
422
423     Row Crypto::getRow(
424             const SqlConnection::DataCommandUniquePtr &selectCommand) const {
425         Row row;
426         row.name = selectCommand->GetColumnString(0);
427         row.ownerLabel = selectCommand->GetColumnString(1);
428         row.exportable = selectCommand->GetColumnInteger(2);
429         row.dataType = DataType(selectCommand->GetColumnInteger(3));
430         row.algorithmType = static_cast<DBCMAlgType>(selectCommand->GetColumnInteger(4));
431         row.encryptionScheme = selectCommand->GetColumnInteger(5);
432         row.iv = selectCommand->GetColumnBlob(6);
433         row.dataSize = selectCommand->GetColumnInteger(7);
434         row.data = selectCommand->GetColumnBlob(8);
435         row.tag = selectCommand->GetColumnBlob(9);
436         return row;
437     }
438
439     PermissionMaskOptional Crypto::getPermissionRow(
440         const Name &name,
441         const Label &ownerLabel,
442         const Label &accessorLabel) const
443     {
444         Try {
445             PermissionTable permissionTable(this->m_connection);
446             return permissionTable.getPermissionRow(name, ownerLabel, accessorLabel);
447         } Catch (SqlConnection::Exception::InvalidColumn) {
448             LogError("Select statement invalid column error");
449         } Catch (SqlConnection::Exception::SyntaxError) {
450             LogError("Couldn't prepare select statement");
451         } Catch (SqlConnection::Exception::InternalError) {
452             LogError("Couldn't execute select statement");
453         }
454         return PermissionMaskOptional();
455     }
456
457     Crypto::RowOptional Crypto::getRow(
458         const Name &name,
459         const Label &ownerLabel,
460         DataType type)
461     {
462         return getRow(name, ownerLabel, type, type);
463     }
464
465     Crypto::RowOptional Crypto::getRow(
466         const Name &name,
467         const Label &ownerLabel,
468         DataType typeRangeStart,
469         DataType typeRangeStop)
470     {
471         Try {
472             SqlConnection::DataCommandUniquePtr selectCommand =
473                     m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL);
474             selectCommand->BindInteger(1, typeRangeStart);
475             selectCommand->BindInteger(2, typeRangeStop);
476
477             // name table reference
478             selectCommand->BindString (101, name.c_str());
479             selectCommand->BindString (102, ownerLabel.c_str());
480
481             if(selectCommand->Step())
482             {
483                 // extract data
484                 Row current_row = getRow(selectCommand);
485
486                 // all okay, proceed
487                 return RowOptional(current_row);
488             } else {
489                 return RowOptional();
490             }
491         } Catch (SqlConnection::Exception::InvalidColumn) {
492             LogError("Select statement invalid column error");
493         } Catch (SqlConnection::Exception::SyntaxError) {
494             LogError("Couldn't prepare select statement");
495         } Catch (SqlConnection::Exception::InternalError) {
496             LogError("Couldn't execute select statement");
497         }
498         ThrowMsg(Crypto::Exception::InternalError,
499                 "Couldn't get row of type <" <<
500                 static_cast<int>(typeRangeStart) << "," <<
501                 static_cast<int>(typeRangeStop)  << ">" <<
502                 " name " << name << " with owner label " << ownerLabel);
503     }
504
505     void Crypto::getRows(
506         const Name &name,
507         const Label &ownerLabel,
508         DataType type,
509         RowVector &output)
510     {
511         getRows(name, ownerLabel, type, type, output);
512     }
513
514     void Crypto::getRows(
515         const Name &name,
516         const Label &ownerLabel,
517         DataType typeRangeStart,
518         DataType typeRangeStop,
519         RowVector &output)
520     {
521         Try {
522             SqlConnection::DataCommandUniquePtr selectCommand =
523                     m_connection->PrepareDataCommand(DB_CMD_OBJECT_SELECT_BY_NAME_AND_LABEL);
524             selectCommand->BindInteger(1, typeRangeStart);
525             selectCommand->BindInteger(2, typeRangeStop);
526
527             // name table reference
528             selectCommand->BindString (101, name.c_str());
529             selectCommand->BindString (102, ownerLabel.c_str());
530
531             while(selectCommand->Step())
532             {
533                 // extract data
534                 output.push_back(getRow(selectCommand));
535             }
536             return;
537         } Catch (SqlConnection::Exception::InvalidColumn) {
538             LogError("Select statement invalid column error");
539         } Catch (SqlConnection::Exception::SyntaxError) {
540             LogError("Couldn't prepare select statement");
541         } Catch (SqlConnection::Exception::InternalError) {
542             LogError("Couldn't execute select statement");
543         }
544         ThrowMsg(Crypto::Exception::InternalError,
545                 "Couldn't get row of type <" <<
546                 static_cast<int>(typeRangeStart) << "," <<
547                 static_cast<int>(typeRangeStop)  << ">" <<
548                 " name " << name << " with owner label " << ownerLabel);
549     }
550
551     void Crypto::listNames(
552         const Label &smackLabel,
553         LabelNameVector& labelNameVector,
554         DataType type)
555     {
556         listNames(smackLabel, labelNameVector, type, type);
557     }
558
559     void Crypto::listNames(
560         const Label &smackLabel,
561         LabelNameVector& labelNameVector,
562         DataType typeRangeStart,
563         DataType typeRangeStop)
564     {
565         Try{
566             Transaction transaction(this);
567             SqlConnection::DataCommandUniquePtr selectCommand =
568                             m_connection->PrepareDataCommand(DB_CMD_NAME_SELECT_BY_TYPE_AND_PERMISSION);
569             selectCommand->BindInteger(1, static_cast<int>(typeRangeStart));
570             selectCommand->BindInteger(2, static_cast<int>(typeRangeStop));
571             selectCommand->BindString(104, smackLabel.c_str());
572             selectCommand->BindInteger(4, static_cast<int>(Permission::READ | Permission::REMOVE));
573
574             while(selectCommand->Step()) {
575                 Label ownerLabel = selectCommand->GetColumnString(0);
576                 Name name = selectCommand->GetColumnString(1);
577                 labelNameVector.push_back(std::make_pair(ownerLabel, name));
578             }
579             return;
580         } Catch (SqlConnection::Exception::InvalidColumn) {
581             LogError("Select statement invalid column error");
582         } Catch (SqlConnection::Exception::SyntaxError) {
583             LogError("Couldn't prepare select statement");
584         } Catch (SqlConnection::Exception::InternalError) {
585             LogError("Couldn't execute select statement");
586         }
587         ThrowMsg(Crypto::Exception::InternalError,
588                 "Couldn't list names of type <" <<
589                 static_cast<int>(typeRangeStart) << "," <<
590                 static_cast<int>(typeRangeStop)  << ">" <<
591                 " accessible to client label " << smackLabel);
592     }
593
594
595
596     void Crypto::saveKey(
597             const Label& label,
598             const RawBuffer &key)
599     {
600         Try {
601             SqlConnection::DataCommandUniquePtr insertCommand =
602                     m_connection->PrepareDataCommand(DB_CMD_KEY_INSERT);
603             insertCommand->BindString(1, label.c_str());
604             insertCommand->BindBlob(2, key);
605             insertCommand->Step();
606             return;
607         } Catch (SqlConnection::Exception::SyntaxError) {
608             LogError("Couldn't prepare insert key statement");
609         } Catch (SqlConnection::Exception::InternalError) {
610             LogError("Couldn't execute insert statement");
611         }
612         ThrowMsg(Crypto::Exception::InternalError,
613                 "Couldn't save key for label " << label);
614     }
615
616     Crypto::RawBufferOptional Crypto::getKey(const Label& label)
617     {
618         Try {
619             SqlConnection::DataCommandUniquePtr selectCommand =
620                     m_connection->PrepareDataCommand(DB_CMD_KEY_SELECT);
621             selectCommand->BindString(1, label.c_str());
622
623             if (selectCommand->Step()) {
624                 return RawBufferOptional(
625                         selectCommand->GetColumnBlob(0));
626             } else {
627                 return RawBufferOptional();
628             }
629
630         } Catch (SqlConnection::Exception::InvalidColumn) {
631             LogError("Select statement invalid column error");
632         } Catch (SqlConnection::Exception::SyntaxError) {
633             LogError("Couldn't prepare insert key statement");
634         } Catch (SqlConnection::Exception::InternalError) {
635             LogError("Couldn't execute insert statement");
636         }
637         ThrowMsg(Crypto::Exception::InternalError,
638                 "Couldn't get key for label " << label);
639     }
640
641     void Crypto::deleteKey(const Label& label) {
642         Try {
643             Transaction transaction(this);
644
645             SqlConnection::DataCommandUniquePtr deleteCommand =
646                     m_connection->PrepareDataCommand(DB_CMD_KEY_DELETE);
647             deleteCommand->BindString(1, label.c_str());
648             deleteCommand->Step();
649
650             NameTable nameTable(this->m_connection);
651             nameTable.deleteAllRows(label);
652
653             transaction.commit();
654             return;
655         } Catch (SqlConnection::Exception::SyntaxError) {
656             LogError("Couldn't prepare insert key statement");
657         } Catch (SqlConnection::Exception::InternalError) {
658             LogError("Couldn't execute insert statement");
659         }
660         ThrowMsg(Crypto::Exception::InternalError,
661                 "Couldn't delete key for label " << label);
662     }
663
664     void Crypto::setPermission(
665             const Name &name,
666             const Label& ownerLabel,
667             const Label& accessorLabel,
668             const PermissionMask permissionMask)
669     {
670         Try {
671             PermissionTable permissionTable(this->m_connection);
672             permissionTable.setPermission(name, ownerLabel, accessorLabel, permissionMask);
673             return;
674         } Catch (SqlConnection::Exception::SyntaxError) {
675             LogError("Couldn't prepare set statement");
676         } Catch (SqlConnection::Exception::InternalError) {
677             LogError("Couldn't execute set statement");
678         }
679         ThrowMsg(Crypto::Exception::InternalError,
680                 "Couldn't set permissions for name " << name );
681     }
682
683
684     void Crypto::SchemaInfo::setVersionInfo() {
685         SqlConnection::DataCommandUniquePtr insertContextCommand =
686                 m_db->m_connection->PrepareDataCommand(DB_CMD_SCHEMA_SET);
687         insertContextCommand->BindString(101, DB_SCHEMA_VERSION_FIELD);
688         insertContextCommand->BindString(103, std::to_string(DB_VERSION_CURRENT).c_str());
689         insertContextCommand->Step();
690     }
691
692     bool Crypto::SchemaInfo::getVersionInfo(int & version) const
693     {
694         // Try..Catch mandatory here - we don't need to escalate the error
695         // if it happens - we just won't return the version, allowing CKM to work
696         Try {
697             SqlConnection::DataCommandUniquePtr selectCommand =
698                     m_db->m_connection->PrepareDataCommand(DB_CMD_SCHEMA_GET);
699             selectCommand->BindString(101, DB_SCHEMA_VERSION_FIELD);
700
701             if(selectCommand->Step()) {
702                 version = static_cast<int>(atoi(selectCommand->GetColumnString(1).c_str()));
703                 return true;
704             }
705         } Catch (SqlConnection::Exception::InvalidColumn) {
706             LogError("Select statement invalid column error");
707         } Catch (SqlConnection::Exception::SyntaxError) {
708             LogError("Couldn't prepare select statement");
709         } Catch (SqlConnection::Exception::InternalError) {
710             LogError("Couldn't execute select statement");
711         }
712         return false;
713     }
714
715     void Crypto::PermissionTable::setPermission(
716             const Name &name,
717             const Label& ownerLabel,
718             const Label& accessorLabel,
719             const PermissionMask permissionMask)
720     {
721         if(permissionMask == Permission::NONE)
722         {
723             // clear permissions
724             SqlConnection::DataCommandUniquePtr deletePermissionCommand =
725                 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_DELETE);
726             deletePermissionCommand->BindString(104, accessorLabel.c_str());
727             deletePermissionCommand->BindString(101, name.c_str());
728             deletePermissionCommand->BindString(102, ownerLabel.c_str());
729             deletePermissionCommand->Step();
730         }
731         else
732         {
733             // add new permissions
734             SqlConnection::DataCommandUniquePtr setPermissionCommand =
735                 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_SET);
736             setPermissionCommand->BindString(104, accessorLabel.c_str());
737             setPermissionCommand->BindInteger(105, static_cast<int>(permissionMask));
738             setPermissionCommand->BindString(101, name.c_str());
739             setPermissionCommand->BindString(102, ownerLabel.c_str());
740             setPermissionCommand->Step();
741         }
742     }
743
744     PermissionMaskOptional Crypto::PermissionTable::getPermissionRow(
745             const Name &name,
746             const Label &ownerLabel,
747             const Label &accessorLabel) const
748     {
749         SqlConnection::DataCommandUniquePtr selectCommand =
750                 m_connection->PrepareDataCommand(DB_CMD_PERMISSION_SELECT);
751         selectCommand->BindString(104, accessorLabel.c_str());
752
753         // name table reference
754         selectCommand->BindString(101, name.c_str());
755         selectCommand->BindString(102, ownerLabel.c_str());
756
757         if(selectCommand->Step())
758         {
759             // there is entry for the <name, ownerLabel> pair
760             return PermissionMaskOptional(PermissionMask(selectCommand->GetColumnInteger(0)));
761         }
762         return PermissionMaskOptional();
763     }
764
765     void Crypto::NameTable::addRow(
766             const Name &name,
767             const Label &ownerLabel)
768     {
769         // insert NAMES item
770         SqlConnection::DataCommandUniquePtr insertNameCommand =
771                 m_connection->PrepareDataCommand(DB_CMD_NAME_INSERT);
772         insertNameCommand->BindString (101, name.c_str());
773         insertNameCommand->BindString (102, ownerLabel.c_str());
774         insertNameCommand->Step();
775     }
776
777     void Crypto::NameTable::deleteRow(
778             const Name &name,
779             const Label &ownerLabel)
780     {
781         SqlConnection::DataCommandUniquePtr deleteCommand =
782                 m_connection->PrepareDataCommand(DB_CMD_NAME_DELETE);
783         deleteCommand->BindString(101, name.c_str());
784         deleteCommand->BindString(102, ownerLabel.c_str());
785
786         // Step() result code does not provide information whether
787         // anything was removed.
788         deleteCommand->Step();
789     }
790
791     void Crypto::NameTable::deleteAllRows(const Label &ownerLabel)
792     {
793         SqlConnection::DataCommandUniquePtr deleteData =
794                 m_connection->PrepareDataCommand(DB_CMD_NAME_DELETE_BY_LABEL);
795         deleteData->BindString(102, ownerLabel.c_str());
796
797         // Step() result code does not provide information whether
798         // anything was removed.
799         deleteData->Step();
800     }
801
802     bool Crypto::NameTable::isPresent(const Name &name, const Label &ownerLabel) const
803     {
804         SqlConnection::DataCommandUniquePtr checkCmd =
805                 m_connection->PrepareDataCommand(DB_CMD_NAME_COUNT_ROWS);
806         checkCmd->BindString(101, name.c_str());
807         checkCmd->BindString(102, ownerLabel.c_str());
808         if(checkCmd->Step()) {
809             int element_count = checkCmd->GetColumnInteger(0);
810             LogDebug("Item name: " << name  << " ownerLabel: " << ownerLabel <<
811                      " hit count: " << element_count);
812             if(element_count > 0)
813                 return true;
814         }
815         return false;
816     }
817
818     void Crypto::ObjectTable::addRow(const Row &row)
819     {
820         SqlConnection::DataCommandUniquePtr insertObjectCommand =
821                 m_connection->PrepareDataCommand(DB_CMD_OBJECT_INSERT);
822         insertObjectCommand->BindInteger(1, row.exportable);
823         insertObjectCommand->BindInteger(2, static_cast<int>(row.dataType));
824         insertObjectCommand->BindInteger(3, static_cast<int>(row.algorithmType));
825         insertObjectCommand->BindInteger(4, row.encryptionScheme);
826         insertObjectCommand->BindBlob   (5, row.iv);
827         insertObjectCommand->BindInteger(6, row.dataSize);
828         insertObjectCommand->BindBlob   (7, row.data);
829         insertObjectCommand->BindBlob   (8, row.tag);
830
831         // name table reference
832         insertObjectCommand->BindString (101, row.name.c_str());
833         insertObjectCommand->BindString (102, row.ownerLabel.c_str());
834
835         insertObjectCommand->Step();
836     }
837 } // namespace DB
838 } // namespace CKM
839
840 #pragma GCC diagnostic pop