Replace dpl asserts with libc ones
[platform/core/security/key-manager.git] / src / manager / dpl / db / src / sql_connection.cpp
1 /*
2  * Copyright (c) 2014-2020 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        sql_connection.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of SQL connection
21  */
22 #pragma GCC diagnostic push
23 #pragma GCC diagnostic warning "-Wdeprecated-declarations"
24
25 #include <stddef.h>
26 #include <dpl/db/sql_connection.h>
27 #include <dpl/db/naive_synchronization_object.h>
28 #include <dpl/scoped_ptr.h>
29 #include <unistd.h>
30 #include <cassert>
31 #include <cstdio>
32 #include <cstdarg>
33 #include <memory>
34 #include <noncopyable.h>
35
36
37 namespace {
38 const int MAX_RETRY = 10;
39 }
40
41 namespace CKM {
42 namespace DB {
43 namespace { // anonymous
44 class ScopedNotifyAll {
45 private:
46         SqlConnection::SynchronizationObject *m_synchronizationObject;
47
48 public:
49         NONCOPYABLE(ScopedNotifyAll)
50
51         explicit ScopedNotifyAll(
52                 SqlConnection::SynchronizationObject *synchronizationObject) :
53                 m_synchronizationObject(synchronizationObject)
54         {
55         }
56
57         ~ScopedNotifyAll()
58         {
59                 if (!m_synchronizationObject)
60                         return;
61
62                 LogPedantic("Notifying after successful synchronize");
63                 m_synchronizationObject->NotifyAll();
64         }
65 };
66 } // namespace anonymous
67
68 SqlConnection::DataCommand::DataCommand(SqlConnection *connection,
69                                                                                 const char *buffer) :
70         m_masterConnection(connection),
71         m_stmt(NULL)
72 {
73         assert(connection != NULL);
74
75         // Notify all after potentially synchronized database connection access
76         ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
77
78         for (int i = 0; i < MAX_RETRY; i++) {
79                 int ret = sqlcipher3_prepare_v2(connection->m_connection,
80                                                                                 buffer, strlen(buffer),
81                                                                                 &m_stmt, NULL);
82
83                 if (ret == SQLCIPHER_OK) {
84                         LogPedantic("Prepared data command: " << buffer);
85
86                         // Increment stored data command count
87                         ++m_masterConnection->m_dataCommandsCount;
88                         return;
89                 } else if (ret == SQLCIPHER_BUSY) {
90                         LogPedantic("Collision occurred while preparing SQL command");
91
92                         // Synchronize if synchronization object is available
93                         if (connection->m_synchronizationObject) {
94                                 LogPedantic("Performing synchronization");
95                                 connection->m_synchronizationObject->Synchronize();
96                                 continue;
97                         }
98
99                         // No synchronization object defined. Fail.
100                 }
101
102                 // Fatal error
103                 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
104
105                 LogError("SQL prepare data command failed");
106                 LogError("    Statement: " << buffer);
107                 LogError("    Error: " << error);
108
109                 ThrowMsg(Exception::SyntaxError, error);
110         }
111
112         LogError("sqlite in the state of possible infinite loop");
113         ThrowMsg(Exception::InternalError, "sqlite permanently busy");
114 }
115
116 SqlConnection::DataCommand::~DataCommand()
117 {
118         LogPedantic("SQL data command finalizing");
119
120         if (sqlcipher3_finalize(m_stmt) != SQLCIPHER_OK)
121                 LogError("Failed to finalize data command");
122
123         // Decrement stored data command count
124         --m_masterConnection->m_dataCommandsCount;
125 }
126
127 void SqlConnection::DataCommand::CheckBindResult(int result)
128 {
129         if (result != SQLCIPHER_OK) {
130                 const char *error = sqlcipher3_errmsg(
131                                                                 m_masterConnection->m_connection);
132
133                 LogError("Failed to bind SQL statement parameter");
134                 LogError("    Error: " << error);
135
136                 ThrowMsg(Exception::SyntaxError, error);
137         }
138 }
139
140 //LCOV_EXCL_START
141 void SqlConnection::DataCommand::BindNull(
142         SqlConnection::ArgumentIndex position)
143 {
144         CheckBindResult(sqlcipher3_bind_null(m_stmt, position));
145         LogPedantic("SQL data command bind null: ["
146                                 << position << "]");
147 }
148 //LCOV_EXCL_STOP
149
150 void SqlConnection::DataCommand::BindInteger(
151         SqlConnection::ArgumentIndex position,
152         int value)
153 {
154         CheckBindResult(sqlcipher3_bind_int(m_stmt, position, value));
155         LogPedantic("SQL data command bind integer: ["
156                                 << position << "] -> " << value);
157 }
158
159 //LCOV_EXCL_START
160 void SqlConnection::DataCommand::BindInt8(
161         SqlConnection::ArgumentIndex position,
162         int8_t value)
163 {
164         CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
165                                                                                 static_cast<int>(value)));
166         LogPedantic("SQL data command bind int8: ["
167                                 << position << "] -> " << value);
168 }
169
170 void SqlConnection::DataCommand::BindInt16(
171         SqlConnection::ArgumentIndex position,
172         int16_t value)
173 {
174         CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
175                                                                                 static_cast<int>(value)));
176         LogPedantic("SQL data command bind int16: ["
177                                 << position << "] -> " << value);
178 }
179
180 void SqlConnection::DataCommand::BindInt32(
181         SqlConnection::ArgumentIndex position,
182         int32_t value)
183 {
184         CheckBindResult(sqlcipher3_bind_int(m_stmt, position,
185                                                                                 static_cast<int>(value)));
186         LogPedantic("SQL data command bind int32: ["
187                                 << position << "] -> " << value);
188 }
189
190 void SqlConnection::DataCommand::BindInt64(
191         SqlConnection::ArgumentIndex position,
192         int64_t value)
193 {
194         CheckBindResult(sqlcipher3_bind_int64(m_stmt, position,
195                                                                                   static_cast<sqlcipher3_int64>(value)));
196         LogPedantic("SQL data command bind int64: ["
197                                 << position << "] -> " << value);
198 }
199
200 void SqlConnection::DataCommand::BindFloat(
201         SqlConnection::ArgumentIndex position,
202         float value)
203 {
204         CheckBindResult(sqlcipher3_bind_double(m_stmt, position,
205                                                                                    static_cast<double>(value)));
206         LogPedantic("SQL data command bind float: ["
207                                 << position << "] -> " << value);
208 }
209
210 void SqlConnection::DataCommand::BindDouble(
211         SqlConnection::ArgumentIndex position,
212         double value)
213 {
214         CheckBindResult(sqlcipher3_bind_double(m_stmt, position, value));
215         LogPedantic("SQL data command bind double: ["
216                                 << position << "] -> " << value);
217 }
218 //LCOV_EXCL_STOP
219
220 void SqlConnection::DataCommand::BindString(
221         SqlConnection::ArgumentIndex position,
222         const char *value)
223 {
224         if (!value) {
225                 BindNull(position);
226                 return;
227         }
228
229         // Assume that text may disappear
230         CheckBindResult(sqlcipher3_bind_text(m_stmt, position,
231                                                                                  value, strlen(value),
232                                                                                  SQLCIPHER_TRANSIENT));
233
234         LogPedantic("SQL data command bind string: ["
235                                 << position << "] -> " << value);
236 }
237
238 void SqlConnection::DataCommand::BindBlob(
239         SqlConnection::ArgumentIndex position,
240         const RawBuffer &raw)
241 {
242         if (raw.size() == 0) {
243                 BindNull(position);
244                 return;
245         }
246
247         // Assume that blob may dissappear
248         CheckBindResult(sqlcipher3_bind_blob(m_stmt, position,
249                                                                                  raw.data(), raw.size(),
250                                                                                  SQLCIPHER_TRANSIENT));
251         LogPedantic("SQL data command bind blob of size: ["
252                                 << position << "] -> " << raw.size());
253 }
254
255 //LCOV_EXCL_START
256 void SqlConnection::DataCommand::BindInteger(
257         SqlConnection::ArgumentIndex position,
258         const boost::optional<int> &value)
259 {
260         if (!value)
261                 BindNull(position);
262         else
263                 BindInteger(position, *value);
264 }
265
266 void SqlConnection::DataCommand::BindInt8(
267         SqlConnection::ArgumentIndex position,
268         const boost::optional<int8_t> &value)
269 {
270         if (!value)
271                 BindNull(position);
272         else
273                 BindInt8(position, *value);
274 }
275
276 void SqlConnection::DataCommand::BindInt16(
277         SqlConnection::ArgumentIndex position,
278         const boost::optional<int16_t> &value)
279 {
280         if (!value)
281                 BindNull(position);
282         else
283                 BindInt16(position, *value);
284 }
285
286 void SqlConnection::DataCommand::BindInt32(
287         SqlConnection::ArgumentIndex position,
288         const boost::optional<int32_t> &value)
289 {
290         if (!value)
291                 BindNull(position);
292         else
293                 BindInt32(position, *value);
294 }
295
296 void SqlConnection::DataCommand::BindInt64(
297         SqlConnection::ArgumentIndex position,
298         const boost::optional<int64_t> &value)
299 {
300         if (!value)
301                 BindNull(position);
302         else
303                 BindInt64(position, *value);
304 }
305
306 void SqlConnection::DataCommand::BindFloat(
307         SqlConnection::ArgumentIndex position,
308         const boost::optional<float> &value)
309 {
310         if (!value)
311                 BindNull(position);
312         else
313                 BindFloat(position, *value);
314 }
315
316 void SqlConnection::DataCommand::BindDouble(
317         SqlConnection::ArgumentIndex position,
318         const boost::optional<double> &value)
319 {
320         if (!value)
321                 BindNull(position);
322         else
323                 BindDouble(position, *value);
324 }
325
326 void SqlConnection::DataCommand::BindBlob(
327         SqlConnection::ArgumentIndex position,
328         const boost::optional<RawBuffer> &value)
329 {
330         if (!!value)
331                 BindBlob(position, *value);
332         else
333                 BindNull(position);
334 }
335 //LCOV_EXCL_STOP
336
337 bool SqlConnection::DataCommand::Step()
338 {
339         // Notify all after potentially synchronized database connection access
340         ScopedNotifyAll notifyAll(
341                 m_masterConnection->m_synchronizationObject.get());
342
343         for (int i = 0; i < MAX_RETRY; i++) {
344                 int ret = sqlcipher3_step(m_stmt);
345
346                 if (ret == SQLCIPHER_ROW) {
347                         LogPedantic("SQL data command step ROW");
348                         return true;
349                 } else if (ret == SQLCIPHER_DONE) {
350                         LogPedantic("SQL data command step DONE");
351                         return false;
352                 } else if (ret == SQLCIPHER_BUSY) {
353                         LogPedantic("Collision occurred while executing SQL command");
354
355                         // Synchronize if synchronization object is available
356                         if (m_masterConnection->m_synchronizationObject) {
357                                 LogPedantic("Performing synchronization");
358
359                                 m_masterConnection->
360                                 m_synchronizationObject->Synchronize();
361
362                                 continue;
363                         }
364
365                         // No synchronization object defined. Fail.
366                 }
367
368                 // Fatal error
369                 const char *error = sqlcipher3_errmsg(m_masterConnection->m_connection);
370
371                 LogError("SQL step data command failed");
372                 LogError("    Error: " << error);
373
374                 ThrowMsg(Exception::InternalError, error);
375         }
376
377         LogError("sqlite in the state of possible infinite loop");
378         ThrowMsg(Exception::InternalError, "sqlite permanently busy");
379 }
380
381 void SqlConnection::DataCommand::Reset()
382 {
383         /*
384          * According to:
385          * http://www.sqllite.org/c3ref/stmt.html
386          *
387          * if last sqlcipher3_step command on this stmt returned an error,
388          * then sqlcipher3_reset will return that error, althought it is not an error.
389          * So sqlcipher3_reset allways succedes.
390          */
391         sqlcipher3_reset(m_stmt);
392
393         LogPedantic("SQL data command reset");
394 }
395
396 void SqlConnection::DataCommand::CheckColumnIndex(
397         SqlConnection::ColumnIndex column)
398 {
399         if (column < 0 || column >= sqlcipher3_column_count(m_stmt))
400                 ThrowMsg(Exception::InvalidColumn, "Column index is out of bounds");
401 }
402
403 //LCOV_EXCL_START
404 bool SqlConnection::DataCommand::IsColumnNull(
405         SqlConnection::ColumnIndex column)
406 {
407         LogPedantic("SQL data command get column type: [" << column << "]");
408         CheckColumnIndex(column);
409         return sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL;
410 }
411 //LCOV_EXCL_STOP
412
413 int SqlConnection::DataCommand::GetColumnInteger(
414         SqlConnection::ColumnIndex column)
415 {
416         LogPedantic("SQL data command get column integer: [" << column << "]");
417         CheckColumnIndex(column);
418         int value = sqlcipher3_column_int(m_stmt, column);
419         LogPedantic("    Value: " << value);
420         return value;
421 }
422
423 //LCOV_EXCL_START
424 int8_t SqlConnection::DataCommand::GetColumnInt8(
425         SqlConnection::ColumnIndex column)
426 {
427         LogPedantic("SQL data command get column int8: [" << column << "]");
428         CheckColumnIndex(column);
429         int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
430         LogPedantic("    Value: " << value);
431         return value;
432 }
433
434 int16_t SqlConnection::DataCommand::GetColumnInt16(
435         SqlConnection::ColumnIndex column)
436 {
437         LogPedantic("SQL data command get column int16: [" << column << "]");
438         CheckColumnIndex(column);
439         int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
440         LogPedantic("    Value: " << value);
441         return value;
442 }
443
444 int32_t SqlConnection::DataCommand::GetColumnInt32(
445         SqlConnection::ColumnIndex column)
446 {
447         LogPedantic("SQL data command get column int32: [" << column << "]");
448         CheckColumnIndex(column);
449         int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
450         LogPedantic("    Value: " << value);
451         return value;
452 }
453
454 int64_t SqlConnection::DataCommand::GetColumnInt64(
455         SqlConnection::ColumnIndex column)
456 {
457         LogPedantic("SQL data command get column int64: [" << column << "]");
458         CheckColumnIndex(column);
459         int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
460         LogPedantic("    Value: " << value);
461         return value;
462 }
463
464 float SqlConnection::DataCommand::GetColumnFloat(
465         SqlConnection::ColumnIndex column)
466 {
467         LogPedantic("SQL data command get column float: [" << column << "]");
468         CheckColumnIndex(column);
469         float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
470         LogPedantic("    Value: " << value);
471         return value;
472 }
473
474 double SqlConnection::DataCommand::GetColumnDouble(
475         SqlConnection::ColumnIndex column)
476 {
477         LogPedantic("SQL data command get column double: [" << column << "]");
478         CheckColumnIndex(column);
479         double value = sqlcipher3_column_double(m_stmt, column);
480         LogPedantic("    Value: " << value);
481         return value;
482 }
483 //LCOV_EXCL_STOP
484
485 std::string SqlConnection::DataCommand::GetColumnString(
486         SqlConnection::ColumnIndex column)
487 {
488         LogPedantic("SQL data command get column string: [" << column << "]");
489         CheckColumnIndex(column);
490
491         const char *value = reinterpret_cast<const char *>(
492                                                         sqlcipher3_column_text(m_stmt, column));
493
494         LogPedantic("Value: " << (value ? value : "NULL"));
495
496         if (value == NULL)
497                 return std::string();
498
499         return std::string(value);
500 }
501
502 RawBuffer SqlConnection::DataCommand::GetColumnBlob(
503         SqlConnection::ColumnIndex column)
504 {
505         LogPedantic("SQL data command get column blog: [" << column << "]");
506         CheckColumnIndex(column);
507
508         const unsigned char *value = reinterpret_cast<const unsigned char *>(
509                                                                          sqlcipher3_column_blob(m_stmt, column));
510
511         if (value == NULL)
512                 return RawBuffer();
513
514         int length = sqlcipher3_column_bytes(m_stmt, column);
515         LogPedantic("Got blob of length: " << length);
516
517         return RawBuffer(value, value + length);
518 }
519
520 //LCOV_EXCL_START
521 boost::optional<int> SqlConnection::DataCommand::GetColumnOptionalInteger(
522         SqlConnection::ColumnIndex column)
523 {
524         LogPedantic("SQL data command get column optional integer: ["
525                                 << column << "]");
526         CheckColumnIndex(column);
527
528         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
529                 return boost::optional<int>();
530
531         int value = sqlcipher3_column_int(m_stmt, column);
532         LogPedantic("    Value: " << value);
533         return boost::optional<int>(value);
534 }
535
536 boost::optional<int8_t> SqlConnection::DataCommand::GetColumnOptionalInt8(
537         SqlConnection::ColumnIndex column)
538 {
539         LogPedantic("SQL data command get column optional int8: ["
540                                 << column << "]");
541         CheckColumnIndex(column);
542
543         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
544                 return boost::optional<int8_t>();
545
546         int8_t value = static_cast<int8_t>(sqlcipher3_column_int(m_stmt, column));
547         LogPedantic("    Value: " << value);
548         return boost::optional<int8_t>(value);
549 }
550
551 boost::optional<int16_t> SqlConnection::DataCommand::GetColumnOptionalInt16(
552         SqlConnection::ColumnIndex column)
553 {
554         LogPedantic("SQL data command get column optional int16: ["
555                                 << column << "]");
556         CheckColumnIndex(column);
557
558         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
559                 return boost::optional<int16_t>();
560
561         int16_t value = static_cast<int16_t>(sqlcipher3_column_int(m_stmt, column));
562         LogPedantic("    Value: " << value);
563         return boost::optional<int16_t>(value);
564 }
565
566 boost::optional<int32_t> SqlConnection::DataCommand::GetColumnOptionalInt32(
567         SqlConnection::ColumnIndex column)
568 {
569         LogPedantic("SQL data command get column optional int32: ["
570                                 << column << "]");
571         CheckColumnIndex(column);
572
573         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
574                 return boost::optional<int32_t>();
575
576         int32_t value = static_cast<int32_t>(sqlcipher3_column_int(m_stmt, column));
577         LogPedantic("    Value: " << value);
578         return boost::optional<int32_t>(value);
579 }
580
581 boost::optional<int64_t> SqlConnection::DataCommand::GetColumnOptionalInt64(
582         SqlConnection::ColumnIndex column)
583 {
584         LogPedantic("SQL data command get column optional int64: ["
585                                 << column << "]");
586         CheckColumnIndex(column);
587
588         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
589                 return boost::optional<int64_t>();
590
591         int64_t value = static_cast<int64_t>(sqlcipher3_column_int64(m_stmt, column));
592         LogPedantic("    Value: " << value);
593         return boost::optional<int64_t>(value);
594 }
595
596 boost::optional<float> SqlConnection::DataCommand::GetColumnOptionalFloat(
597         SqlConnection::ColumnIndex column)
598 {
599         LogPedantic("SQL data command get column optional float: ["
600                                 << column << "]");
601         CheckColumnIndex(column);
602
603         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
604                 return boost::optional<float>();
605
606         float value = static_cast<float>(sqlcipher3_column_double(m_stmt, column));
607         LogPedantic("    Value: " << value);
608         return boost::optional<float>(value);
609 }
610
611 boost::optional<double> SqlConnection::DataCommand::GetColumnOptionalDouble(
612         SqlConnection::ColumnIndex column)
613 {
614         LogPedantic("SQL data command get column optional double: ["
615                                 << column << "]");
616         CheckColumnIndex(column);
617
618         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
619                 return boost::optional<double>();
620
621         double value = sqlcipher3_column_double(m_stmt, column);
622         LogPedantic("    Value: " << value);
623         return boost::optional<double>(value);
624 }
625
626 boost::optional<RawBuffer> SqlConnection::DataCommand::GetColumnOptionalBlob(
627         SqlConnection::ColumnIndex column)
628 {
629         LogPedantic("SQL data command get column blog: [" << column << "]");
630         CheckColumnIndex(column);
631
632         if (sqlcipher3_column_type(m_stmt, column) == SQLCIPHER_NULL)
633                 return boost::optional<RawBuffer>();
634
635         const unsigned char *value = reinterpret_cast<const unsigned char *>(
636                                                                          sqlcipher3_column_blob(m_stmt, column));
637
638         int length = sqlcipher3_column_bytes(m_stmt, column);
639         LogPedantic("Got blob of length: " << length);
640
641         RawBuffer temp(value, value + length);
642         return boost::optional<RawBuffer>(temp);
643 }
644 //LCOV_EXCL_STOP
645
646 void SqlConnection::Connect(const std::string &address,
647                                                         Flag::Option flag)
648 {
649         if (m_connection != NULL) {
650                 LogPedantic("Already connected.");
651                 return;
652         }
653
654         LogPedantic("Connecting to DB: " << address << "...");
655
656         // Connect to database
657         int result;
658         result = sqlcipher3_open_v2(
659                                  address.c_str(),
660                                  &m_connection,
661                                  flag,
662                                  NULL);
663
664         if (result == SQLCIPHER_OK) {
665                 LogPedantic("Connected to DB");
666         } else {
667                 LogError("Failed to connect to DB!");
668                 ThrowMsg(Exception::ConnectionBroken, address);
669         }
670
671         // Enable foreign keys
672         TurnOnForeignKeys();
673 }
674
675 const std::string SQLCIPHER_RAW_PREFIX = "x'";
676 const std::string SQLCIPHER_RAW_SUFIX = "'";
677 const std::size_t SQLCIPHER_RAW_DATA_SIZE = 32;
678
679 RawBuffer rawToHexString(const RawBuffer &raw)
680 {
681         return hexDump<RawBuffer, true>(raw);
682 }
683
684 RawBuffer createHexPass(const RawBuffer &rawPass)
685 {
686         // We are required to pass 64byte long hex password made out of 32byte raw
687         // binary data
688         RawBuffer output;
689         std::copy(SQLCIPHER_RAW_PREFIX.begin(), SQLCIPHER_RAW_PREFIX.end(),
690                           std::back_inserter(output));
691
692         RawBuffer password = rawToHexString(rawPass);
693
694         std::copy(password.begin(), password.end(),
695                           std::back_inserter(output));
696
697         std::copy(SQLCIPHER_RAW_SUFIX.begin(), SQLCIPHER_RAW_SUFIX.end(),
698                           std::back_inserter(output));
699
700         return output;
701 }
702
703 void SqlConnection::SetKey(const RawBuffer &rawPass)
704 {
705         if (m_connection == NULL) {
706                 LogPedantic("Cannot set key. No connection to DB!");
707                 return;
708         }
709
710         if (rawPass.size() != SQLCIPHER_RAW_DATA_SIZE)
711                 ThrowMsg(Exception::InvalidArguments,
712                                  "Binary data for raw password should be 32 bytes long.");
713
714         RawBuffer pass = createHexPass(rawPass);
715         int result = sqlcipher3_key(m_connection, pass.data(), pass.size());
716
717         if (result == SQLCIPHER_OK) {
718                 LogPedantic("Set key on DB");
719         } else {
720                 //sqlcipher3_key fails only when m_connection == NULL || key == NULL ||
721                 //                            key length == 0
722                 LogError("Failed to set key on DB");
723                 ThrowMsg(Exception::InvalidArguments, result);
724         }
725
726         m_isKeySet = true;
727 };
728
729 //LCOV_EXCL_START
730 void SqlConnection::ResetKey(const RawBuffer &rawPassOld,
731                                                          const RawBuffer &rawPassNew)
732 {
733         if (m_connection == NULL) {
734                 LogPedantic("Cannot reset key. No connection to DB!");
735                 return;
736         }
737
738         // Binary data for raw password should be 32 bytes long.
739         assert(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
740                rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE);
741
742
743         // sqlcipher3_rekey requires for key to be already set
744         if (!m_isKeySet)
745                 SetKey(rawPassOld);
746
747         RawBuffer pass = createHexPass(rawPassNew);
748         int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
749
750         if (result == SQLCIPHER_OK) {
751                 LogPedantic("Reset key on DB");
752         } else {
753                 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
754                 //                              key length == 0
755                 LogError("Failed to reset key on DB");
756                 ThrowMsg(Exception::InvalidArguments, result);
757         }
758 }
759 //LCOV_EXCL_STOP
760
761 void SqlConnection::Disconnect()
762 {
763         if (m_connection == NULL) {
764                 LogPedantic("Already disconnected.");
765                 return;
766         }
767
768         LogPedantic("Disconnecting from DB...");
769
770         // All stored data commands must be deleted before disconnect
771         assert(m_dataCommandsCount == 0);
772
773         int result;
774
775         result = sqlcipher3_close(m_connection);
776
777         if (result != SQLCIPHER_OK) {
778                 const char *error = sqlcipher3_errmsg(m_connection);
779                 LogError("SQL close failed");
780                 LogError("    Error: " << error);
781                 Throw(Exception::InternalError);
782         }
783
784         m_connection = NULL;
785
786         LogPedantic("Disconnected from DB");
787 }
788
789 bool SqlConnection::CheckTableExist(const char *tableName)
790 {
791         if (m_connection == NULL) {
792                 LogPedantic("Cannot execute command. Not connected to DB!");
793                 return false;
794         }
795
796         DataCommandUniquePtr command =
797                 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
798
799         command->BindString(1, tableName);
800
801         if (!command->Step()) {
802                 LogPedantic("No matching records in table");
803                 return false;
804         }
805
806         return command->GetColumnString(0) == tableName;
807 }
808
809 SqlConnection::SqlConnection(const std::string &address,
810                                                          Flag::Option option,
811                                                          SynchronizationObject *synchronizationObject) :
812         m_connection(NULL),
813         m_dataCommandsCount(0),
814         m_synchronizationObject(synchronizationObject),
815         m_isKeySet(false)
816 {
817         LogPedantic("Opening database connection to: " << address);
818
819         // Connect to DB
820         SqlConnection::Connect(address, option);
821
822         if (!m_synchronizationObject)
823                 LogPedantic("No synchronization object defined");
824 }
825
826 SqlConnection::~SqlConnection()
827 {
828         LogPedantic("Closing database connection");
829
830         // Disconnect from DB
831         try {
832                 SqlConnection::Disconnect();
833         } catch (const Exception::Base &) {
834                 LogError("Failed to disconnect from database");
835         }
836 }
837
838 //LCOV_EXCL_START
839 int SqlConnection::Output::Callback(void *param, int columns, char **values,
840                                                                         char **names)
841 {
842         if (param)
843                 static_cast<Output *>(param)->SetResults(columns, values, names);
844
845         return 0;
846 }
847
848 void SqlConnection::Output::SetResults(int columns, char **values, char **names)
849 {
850         if (m_names.empty()) {
851                 for (int i = 0; i < columns; i++)
852                         m_names.push_back(names[i] ? names[i] : "NULL");
853         }
854
855         Row row;
856
857         for (int i = 0; i < columns; i++)
858                 row.push_back(values[i] ? values[i] : "NULL");
859
860         m_values.push_back(std::move(row));
861 }
862 //LCOV_EXCL_STOP
863
864 void SqlConnection::ExecCommandHelper(Output *out, const char *format,
865                                                                           va_list args)
866 {
867         if (m_connection == NULL) {
868                 LogError("Cannot execute command. Not connected to DB!");
869                 return;
870         }
871
872         if (format == NULL) {
873                 LogError("Null query!");
874                 ThrowMsg(Exception::SyntaxError, "Null statement");
875         }
876
877         char *query;
878
879         if (vasprintf(&query, format, args) == -1) {
880                 LogError("Failed to allocate statement string");
881                 return;
882         }
883
884         CharUniquePtr queryPtr(query);
885
886         LogPedantic("Executing SQL command: " << queryPtr.get());
887
888         // Notify all after potentially synchronized database connection access
889         ScopedNotifyAll notifyAll(m_synchronizationObject.get());
890
891         for (int i = 0; i < MAX_RETRY; i++) {
892                 char *errorBuffer;
893                 int ret = sqlcipher3_exec(m_connection,
894                                                                   queryPtr.get(),
895                                                                   out ? &Output::Callback : NULL,
896                                                                   out,
897                                                                   &errorBuffer);
898
899                 std::string errorMsg;
900
901                 // Take allocated error buffer
902                 if (errorBuffer != NULL) {
903                         errorMsg = errorBuffer;
904                         sqlcipher3_free(errorBuffer);
905                 }
906
907                 if (ret == SQLCIPHER_OK)
908                         return;
909
910                 if (ret == SQLCIPHER_BUSY) {
911                         LogPedantic("Collision occurred while executing SQL command");
912
913                         // Synchronize if synchronization object is available
914                         if (m_synchronizationObject) {
915                                 LogPedantic("Performing synchronization");
916                                 m_synchronizationObject->Synchronize();
917                                 continue;
918                         }
919
920                         // No synchronization object defined. Fail.
921                 }
922
923                 // Fatal error
924                 LogError("Failed to execute SQL command. Error: " << errorMsg);
925                 ThrowMsg(Exception::SyntaxError, errorMsg);
926         }
927
928         LogError("sqlite in the state of possible infinite loop");
929         ThrowMsg(Exception::InternalError, "sqlite permanently busy");
930 }
931
932 //LCOV_EXCL_START
933 void SqlConnection::ExecCommand(Output *out, const char *format, ...)
934 {
935         va_list args;
936         va_start(args, format);
937         try {
938                 ExecCommandHelper(out, format, args);
939         } catch (...) {
940                 va_end(args);
941                 throw;
942         }
943         va_end(args);
944 }
945 //LCOV_EXCL_STOP
946
947 void SqlConnection::ExecCommand(const char *format, ...)
948 {
949         va_list args;
950         va_start(args, format);
951         try {
952                 ExecCommandHelper(NULL, format, args);
953         } catch (...) {
954                 va_end(args);
955                 throw;
956         }
957         va_end(args);
958 }
959
960 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
961         const char *format,
962         ...)
963 {
964         if (m_connection == NULL) {
965                 LogError("Cannot execute data command. Not connected to DB!");
966                 return DataCommandUniquePtr();
967         }
968
969         char *rawBuffer;
970
971         va_list args;
972         va_start(args, format);
973
974         if (vasprintf(&rawBuffer, format, args) == -1)
975                 rawBuffer = NULL;
976
977         va_end(args);
978
979         CharUniquePtr buffer(rawBuffer);
980
981         if (!buffer) {
982                 LogError("Failed to allocate statement string");
983                 return DataCommandUniquePtr();
984         }
985
986         LogPedantic("Executing SQL data command: " << buffer.get());
987
988         return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
989 }
990
991 //LCOV_EXCL_START
992 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
993 {
994         return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
995 }
996 //LCOV_EXCL_STOP
997
998 void SqlConnection::TurnOnForeignKeys()
999 {
1000         ExecCommand("PRAGMA foreign_keys = ON;");
1001 }
1002
1003 void SqlConnection::BeginTransaction()
1004 {
1005         ExecCommand("BEGIN;");
1006 }
1007
1008 void SqlConnection::RollbackTransaction()
1009 {
1010         ExecCommand("ROLLBACK;");
1011 }
1012
1013 void SqlConnection::CommitTransaction()
1014 {
1015         ExecCommand("COMMIT;");
1016 }
1017
1018 SqlConnection::SynchronizationObject *
1019 SqlConnection::AllocDefaultSynchronizationObject()
1020 {
1021         return new NaiveSynchronizationObject();
1022 }
1023 } // namespace DB
1024 } // namespace CKM
1025
1026 #pragma GCC diagnostic pop