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