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