Refactor RawBuffer hex dumps
[platform/core/security/key-manager.git] / src / manager / dpl / db / src / sql_connection.cpp
1 /*
2  * Copyright (c) 2014-2019 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/assert.h>
29 #include <dpl/scoped_ptr.h>
30 #include <unistd.h>
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         AssertMsg(rawPassOld.size() == SQLCIPHER_RAW_DATA_SIZE &&
739                           rawPassNew.size() == SQLCIPHER_RAW_DATA_SIZE,
740                           "Binary data for raw password should be 32 bytes long.");
741
742         // sqlcipher3_rekey requires for key to be already set
743         if (!m_isKeySet)
744                 SetKey(rawPassOld);
745
746         RawBuffer pass = createHexPass(rawPassNew);
747         int result = sqlcipher3_rekey(m_connection, pass.data(), pass.size());
748
749         if (result == SQLCIPHER_OK) {
750                 LogPedantic("Reset key on DB");
751         } else {
752                 //sqlcipher3_rekey fails only when m_connection == NULL || key == NULL ||
753                 //                              key length == 0
754                 LogError("Failed to reset key on DB");
755                 ThrowMsg(Exception::InvalidArguments, result);
756         }
757 }
758 //LCOV_EXCL_STOP
759
760 void SqlConnection::Disconnect()
761 {
762         if (m_connection == NULL) {
763                 LogPedantic("Already disconnected.");
764                 return;
765         }
766
767         LogPedantic("Disconnecting from DB...");
768
769         // All stored data commands must be deleted before disconnect
770         AssertMsg(m_dataCommandsCount == 0,
771                           "All stored procedures must be deleted"
772                           " before disconnecting SqlConnection");
773
774         int result;
775
776         result = sqlcipher3_close(m_connection);
777
778         if (result != SQLCIPHER_OK) {
779                 const char *error = sqlcipher3_errmsg(m_connection);
780                 LogError("SQL close failed");
781                 LogError("    Error: " << error);
782                 Throw(Exception::InternalError);
783         }
784
785         m_connection = NULL;
786
787         LogPedantic("Disconnected from DB");
788 }
789
790 bool SqlConnection::CheckTableExist(const char *tableName)
791 {
792         if (m_connection == NULL) {
793                 LogPedantic("Cannot execute command. Not connected to DB!");
794                 return false;
795         }
796
797         DataCommandUniquePtr command =
798                 PrepareDataCommand("select tbl_name from sqlcipher_master where name=?;");
799
800         command->BindString(1, tableName);
801
802         if (!command->Step()) {
803                 LogPedantic("No matching records in table");
804                 return false;
805         }
806
807         return command->GetColumnString(0) == tableName;
808 }
809
810 SqlConnection::SqlConnection(const std::string &address,
811                                                          Flag::Option option,
812                                                          SynchronizationObject *synchronizationObject) :
813         m_connection(NULL),
814         m_dataCommandsCount(0),
815         m_synchronizationObject(synchronizationObject),
816         m_isKeySet(false)
817 {
818         LogPedantic("Opening database connection to: " << address);
819
820         // Connect to DB
821         SqlConnection::Connect(address, option);
822
823         if (!m_synchronizationObject)
824                 LogPedantic("No synchronization object defined");
825 }
826
827 SqlConnection::~SqlConnection()
828 {
829         LogPedantic("Closing database connection");
830
831         // Disconnect from DB
832         try {
833                 SqlConnection::Disconnect();
834         } catch (const Exception::Base &) {
835                 LogError("Failed to disconnect from database");
836         }
837 }
838
839 //LCOV_EXCL_START
840 int SqlConnection::Output::Callback(void *param, int columns, char **values,
841                                                                         char **names)
842 {
843         if (param)
844                 static_cast<Output *>(param)->SetResults(columns, values, names);
845
846         return 0;
847 }
848
849 void SqlConnection::Output::SetResults(int columns, char **values, char **names)
850 {
851         if (m_names.empty()) {
852                 for (int i = 0; i < columns; i++)
853                         m_names.push_back(names[i] ? names[i] : "NULL");
854         }
855
856         Row row;
857
858         for (int i = 0; i < columns; i++)
859                 row.push_back(values[i] ? values[i] : "NULL");
860
861         m_values.push_back(std::move(row));
862 }
863 //LCOV_EXCL_STOP
864
865 void SqlConnection::ExecCommandHelper(Output *out, const char *format,
866                                                                           va_list args)
867 {
868         if (m_connection == NULL) {
869                 LogError("Cannot execute command. Not connected to DB!");
870                 return;
871         }
872
873         if (format == NULL) {
874                 LogError("Null query!");
875                 ThrowMsg(Exception::SyntaxError, "Null statement");
876         }
877
878         char *query;
879
880         if (vasprintf(&query, format, args) == -1) {
881                 LogError("Failed to allocate statement string");
882                 return;
883         }
884
885         CharUniquePtr queryPtr(query);
886
887         LogPedantic("Executing SQL command: " << queryPtr.get());
888
889         // Notify all after potentially synchronized database connection access
890         ScopedNotifyAll notifyAll(m_synchronizationObject.get());
891
892         for (int i = 0; i < MAX_RETRY; i++) {
893                 char *errorBuffer;
894                 int ret = sqlcipher3_exec(m_connection,
895                                                                   queryPtr.get(),
896                                                                   out ? &Output::Callback : NULL,
897                                                                   out,
898                                                                   &errorBuffer);
899
900                 std::string errorMsg;
901
902                 // Take allocated error buffer
903                 if (errorBuffer != NULL) {
904                         errorMsg = errorBuffer;
905                         sqlcipher3_free(errorBuffer);
906                 }
907
908                 if (ret == SQLCIPHER_OK)
909                         return;
910
911                 if (ret == SQLCIPHER_BUSY) {
912                         LogPedantic("Collision occurred while executing SQL command");
913
914                         // Synchronize if synchronization object is available
915                         if (m_synchronizationObject) {
916                                 LogPedantic("Performing synchronization");
917                                 m_synchronizationObject->Synchronize();
918                                 continue;
919                         }
920
921                         // No synchronization object defined. Fail.
922                 }
923
924                 // Fatal error
925                 LogError("Failed to execute SQL command. Error: " << errorMsg);
926                 ThrowMsg(Exception::SyntaxError, errorMsg);
927         }
928
929         LogError("sqlite in the state of possible infinite loop");
930         ThrowMsg(Exception::InternalError, "sqlite permanently busy");
931 }
932
933 //LCOV_EXCL_START
934 void SqlConnection::ExecCommand(Output *out, const char *format, ...)
935 {
936         va_list args;
937         va_start(args, format);
938         try {
939                 ExecCommandHelper(out, format, args);
940         } catch (...) {
941                 va_end(args);
942                 throw;
943         }
944         va_end(args);
945 }
946 //LCOV_EXCL_STOP
947
948 void SqlConnection::ExecCommand(const char *format, ...)
949 {
950         va_list args;
951         va_start(args, format);
952         try {
953                 ExecCommandHelper(NULL, format, args);
954         } catch (...) {
955                 va_end(args);
956                 throw;
957         }
958         va_end(args);
959 }
960
961 SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
962         const char *format,
963         ...)
964 {
965         if (m_connection == NULL) {
966                 LogError("Cannot execute data command. Not connected to DB!");
967                 return DataCommandUniquePtr();
968         }
969
970         char *rawBuffer;
971
972         va_list args;
973         va_start(args, format);
974
975         if (vasprintf(&rawBuffer, format, args) == -1)
976                 rawBuffer = NULL;
977
978         va_end(args);
979
980         CharUniquePtr buffer(rawBuffer);
981
982         if (!buffer) {
983                 LogError("Failed to allocate statement string");
984                 return DataCommandUniquePtr();
985         }
986
987         LogPedantic("Executing SQL data command: " << buffer.get());
988
989         return DataCommandUniquePtr(new DataCommand(this, buffer.get()));
990 }
991
992 //LCOV_EXCL_START
993 SqlConnection::RowID SqlConnection::GetLastInsertRowID() const
994 {
995         return static_cast<RowID>(sqlcipher3_last_insert_rowid(m_connection));
996 }
997 //LCOV_EXCL_STOP
998
999 void SqlConnection::TurnOnForeignKeys()
1000 {
1001         ExecCommand("PRAGMA foreign_keys = ON;");
1002 }
1003
1004 void SqlConnection::BeginTransaction()
1005 {
1006         ExecCommand("BEGIN;");
1007 }
1008
1009 void SqlConnection::RollbackTransaction()
1010 {
1011         ExecCommand("ROLLBACK;");
1012 }
1013
1014 void SqlConnection::CommitTransaction()
1015 {
1016         ExecCommand("COMMIT;");
1017 }
1018
1019 SqlConnection::SynchronizationObject *
1020 SqlConnection::AllocDefaultSynchronizationObject()
1021 {
1022         return new NaiveSynchronizationObject();
1023 }
1024 } // namespace DB
1025 } // namespace CKM
1026
1027 #pragma GCC diagnostic pop