Alexandre Lision | 7fd5d3d | 2013-12-04 13:06:40 -0500 | [diff] [blame] | 1 | /* |
Alexandre Lision | 907ed2e | 2014-02-04 10:33:09 -0500 | [diff] [blame] | 2 | Copyright (C) 2012-2013 Werner Dittmann |
| 3 | |
| 4 | This program is free software: you can redistribute it and/or modify |
| 5 | it under the terms of the GNU Lesser General Public License as published by |
| 6 | the Free Software Foundation, either version 3 of the License, or |
| 7 | (at your option) any later version. |
| 8 | |
| 9 | This program is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License |
| 15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | */ |
| 17 | |
| 18 | /* |
| 19 | * Authors: Werner Dittmann <Werner.Dittmann@t-online.de> |
Alexandre Lision | 7fd5d3d | 2013-12-04 13:06:40 -0500 | [diff] [blame] | 20 | */ |
| 21 | |
| 22 | #include <stdio.h> |
| 23 | #include <stdlib.h> |
| 24 | #include <stdint.h> |
| 25 | #include <string.h> |
| 26 | #include <time.h> |
Alexandre Lision | 907ed2e | 2014-02-04 10:33:09 -0500 | [diff] [blame] | 27 | #include <sqlite3.h> |
Alexandre Lision | 7fd5d3d | 2013-12-04 13:06:40 -0500 | [diff] [blame] | 28 | |
| 29 | #include <crypto/zrtpDH.h> |
| 30 | |
| 31 | #include <libzrtpcpp/zrtpB64Encode.h> |
| 32 | #include <libzrtpcpp/zrtpB64Decode.h> |
| 33 | |
| 34 | #include <libzrtpcpp/zrtpCacheDbBackend.h> |
| 35 | |
| 36 | /* Some ported SQLite3 libs do not support the _v2 variants */ |
| 37 | #define SQLITE_USE_V2 |
| 38 | |
| 39 | #ifdef SQLITE_USE_V2 |
| 40 | #define SQLITE_PREPARE sqlite3_prepare_v2 |
| 41 | #else |
| 42 | #define SQLITE_PREPARE sqlite3_prepare |
| 43 | #endif |
| 44 | |
| 45 | #if defined(_WIN32) || defined(_WIN64) |
| 46 | # define snprintf _snprintf |
| 47 | #endif |
| 48 | |
| 49 | #ifdef TRANSACTIONS |
| 50 | static const char *beginTransactionSql = "BEGIN TRANSACTION;"; |
| 51 | static const char *commitTransactionSql = "COMMIT;"; |
| 52 | #endif |
| 53 | |
| 54 | /* |
| 55 | * The database backend uses the following definitions if it implements the localZid storage. |
| 56 | */ |
| 57 | |
| 58 | /* The type field in zrtpIdOwn stores the following values */ |
| 59 | static const int32_t localZidStandard = 1; /* this local ZID is not tied to a specific account */ |
| 60 | static const int32_t localZidWithAccount = 2; |
| 61 | |
| 62 | /* Default data for account info if none specified */ |
| 63 | static const char *defaultAccountString = "_STANDARD_"; |
| 64 | |
| 65 | |
| 66 | /* ***************************************************************************** |
| 67 | * The SQLite master table. |
| 68 | * |
| 69 | * Used to check if we have valid ZRTP cache tables. |
| 70 | */ |
| 71 | static char *lookupTables = "SELECT name FROM sqlite_master WHERE type='table' AND name='zrtpIdOwn';"; |
| 72 | |
| 73 | |
| 74 | /* ***************************************************************************** |
| 75 | * SQL statements to process the zrtpIdOwn table. |
| 76 | */ |
Alexandre Lision | 907ed2e | 2014-02-04 10:33:09 -0500 | [diff] [blame] | 77 | static const char *dropZrtpIdOwn = "DROP TABLE zrtpIdOwn;"; |
| 78 | |
Alexandre Lision | 7fd5d3d | 2013-12-04 13:06:40 -0500 | [diff] [blame] | 79 | /* SQLite doesn't care about the VARCHAR length. */ |
| 80 | static char *createZrtpIdOwn = "CREATE TABLE zrtpIdOwn(localZid CHAR(18), type INTEGER, accountInfo VARCHAR(1000));"; |
| 81 | |
| 82 | static char *selectZrtpIdOwn = "SELECT localZid FROM zrtpIdOwn WHERE type = ?1 AND accountInfo = ?2;"; |
| 83 | static char *insertZrtpIdOwn = "INSERT INTO zrtpIdOwn (localZid, type, accountInfo) VALUES (?1, ?2, ?3);"; |
| 84 | |
| 85 | |
| 86 | /* ***************************************************************************** |
| 87 | * SQL statements to process the remoteId table. |
| 88 | */ |
| 89 | static const char *dropZrtpIdRemote = "DROP TABLE zrtpIdRemote;"; |
| 90 | |
| 91 | static const char *createZrtpIdRemote = |
| 92 | "CREATE TABLE zrtpIdRemote " |
| 93 | "(remoteZid CHAR(16), localZid CHAR(16), flags INTEGER," |
| 94 | "rs1 BLOB(32), rs1LastUsed TIMESTAMP, rs1TimeToLive TIMESTAMP," |
| 95 | "rs2 BLOB(32), rs2LastUsed TIMESTAMP, rs2TimeToLive TIMESTAMP," |
| 96 | "mitmKey BLOB(32), mitmLastUsed TIMESTAMP, secureSince TIMESTAMP, preshCounter INTEGER);"; |
| 97 | |
| 98 | static const char *selectZrtpIdRemoteAll = |
| 99 | "SELECT flags," |
| 100 | "rs1, strftime('%s', rs1LastUsed, 'unixepoch'), strftime('%s', rs1TimeToLive, 'unixepoch')," |
| 101 | "rs2, strftime('%s', rs2LastUsed, 'unixepoch'), strftime('%s', rs2TimeToLive, 'unixepoch')," |
| 102 | "mitmKey, strftime('%s', mitmLastUsed, 'unixepoch'), strftime('%s', secureSince, 'unixepoch')," |
| 103 | "preshCounter " |
| 104 | "FROM zrtpIdRemote WHERE remoteZid=?1 AND localZid=?2;"; |
| 105 | |
| 106 | static const char *insertZrtpIdRemote = |
| 107 | "INSERT INTO zrtpIdRemote " |
| 108 | "(remoteZid, localZid, flags," |
| 109 | "rs1, rs1LastUsed, rs1TimeToLive," |
| 110 | "rs2, rs2LastUsed, rs2TimeToLive," |
| 111 | "mitmKey, mitmLastUsed, secureSince, preshCounter)" |
| 112 | "VALUES" |
| 113 | "(?1, ?12, ?2," |
| 114 | "?3, strftime('%s', ?4, 'unixepoch'), strftime('%s', ?5, 'unixepoch')," |
| 115 | "?6, strftime('%s', ?7, 'unixepoch'), strftime('%s', ?8, 'unixepoch')," |
| 116 | "?9, strftime('%s', ?10, 'unixepoch'), strftime('%s', ?11, 'unixepoch'), ?13);"; |
| 117 | |
| 118 | static const char *updateZrtpIdRemote = |
| 119 | "UPDATE zrtpIdRemote SET " |
| 120 | "flags=?2," |
| 121 | "rs1=?3, rs1LastUsed=strftime('%s', ?4, 'unixepoch'), rs1TimeToLive=strftime('%s', ?5, 'unixepoch')," |
| 122 | "rs2=?6, rs2LastUsed=strftime('%s', ?7, 'unixepoch'), rs2TimeToLive=strftime('%s', ?8, 'unixepoch')," |
| 123 | "mitmKey=?9, mitmLastUsed=strftime('%s', ?10, 'unixepoch')," |
| 124 | "secureSince=strftime('%s', ?11, 'unixepoch'), preshCounter=?13 " |
| 125 | "WHERE remoteZid=?1 AND localZid=?12;"; |
| 126 | |
| 127 | |
| 128 | /* ***************************************************************************** |
| 129 | * SQL statements to process the name table. |
| 130 | * |
| 131 | * The name tables holds free format information and binds it to the combination |
| 132 | * of local, remote ZIDs and an optional account information. |
| 133 | */ |
| 134 | static const char *dropZrtpNames = "DROP TABLE zrtpNames;"; |
| 135 | |
| 136 | static const char *createZrtpNames = |
| 137 | "CREATE TABLE zrtpNames " |
| 138 | "(remoteZid CHAR(16), localZid CHAR(16), flags INTEGER, " |
| 139 | "lastUpdate TIMESTAMP, accountInfo VARCHAR(1000), name VARCHAR(1000));"; |
| 140 | |
| 141 | static const char *selectZrtpNames = |
| 142 | "SELECT flags, strftime('%s', lastUpdate, 'unixepoch'), name " |
| 143 | "FROM zrtpNames " |
| 144 | "WHERE remoteZid=?1 AND localZid=?2 AND accountInfo=?3;"; |
| 145 | |
| 146 | static const char *insertZrtpNames = |
| 147 | "INSERT INTO zrtpNames " |
| 148 | "(remoteZid, localZid, flags, lastUpdate, accountInfo, name)" |
| 149 | "VALUES" |
| 150 | "(?1, ?2, ?4, strftime('%s', ?5, 'unixepoch'), ?3, ?6);"; |
| 151 | |
| 152 | static const char *updateZrtpNames = |
| 153 | "UPDATE zrtpNames SET " |
| 154 | "flags=?4," |
| 155 | "lastUpdate=strftime('%s', ?5, 'unixepoch'), name=?6 " |
| 156 | "WHERE remoteZid=?1 AND localZid=?2 AND accountInfo=?3;"; |
| 157 | |
| 158 | |
| 159 | /* ***************************************************************************** |
| 160 | * A few helping macros. |
| 161 | * These macros require some names/patterns in the methods that use these |
| 162 | * macros: |
| 163 | * |
| 164 | * ERRMSG requires: |
| 165 | * - a variable with name "db" is the pointer to sqlite3 |
| 166 | * - a char* with name "errString" points to a buffer of at least SQL_CACHE_ERR_BUFF_SIZE chars |
| 167 | * |
| 168 | * SQLITE_CHK requires: |
| 169 | * - a cleanup label, the macro goes to that label in case of error |
| 170 | * - an integer (int) variable with name "rc" that stores return codes from sqlite |
| 171 | * - ERRMSG |
| 172 | */ |
| 173 | #define ERRMSG {if (errString) snprintf(errString, (size_t)DB_CACHE_ERR_BUFF_SIZE, \ |
| 174 | "SQLite3 error: %s, line: %d, error message: %s\n", __FILE__, __LINE__, sqlite3_errmsg(db));} |
| 175 | #define SQLITE_CHK(func) { \ |
| 176 | rc = (func); \ |
| 177 | if(rc != SQLITE_OK) { \ |
| 178 | ERRMSG; \ |
| 179 | goto cleanup; \ |
| 180 | } \ |
| 181 | } |
| 182 | |
| 183 | static int b64Encode(const uint8_t *binData, int32_t binLength, char *b64Data, int32_t b64Length) |
| 184 | { |
| 185 | base64_encodestate _state; |
| 186 | int codelength; |
| 187 | |
| 188 | base64_init_encodestate(&_state, 0); |
| 189 | codelength = base64_encode_block(binData, binLength, b64Data, &_state); |
| 190 | codelength += base64_encode_blockend(b64Data+codelength, &_state); |
| 191 | |
| 192 | return codelength; |
| 193 | } |
| 194 | |
| 195 | static int b64Decode(const char *b64Data, int32_t b64length, uint8_t *binData, int32_t binLength) |
| 196 | { |
| 197 | base64_decodestate _state; |
| 198 | int codelength; |
| 199 | |
| 200 | base64_init_decodestate(&_state); |
| 201 | codelength = base64_decode_block(b64Data, b64length, binData, &_state); |
| 202 | return codelength; |
| 203 | } |
| 204 | |
| 205 | #ifdef TRANSACTIONS |
| 206 | static int beginTransaction(sqlite3 *db, char* errString) |
| 207 | { |
| 208 | sqlite3_stmt *stmt; |
| 209 | int rc; |
| 210 | |
| 211 | SQLITE_CHK(SQLITE_PREPARE(db, beginTransactionSql, strlen(beginTransactionSql)+1, &stmt, NULL)); |
| 212 | |
| 213 | rc = sqlite3_step(stmt); |
| 214 | sqlite3_finalize(stmt); |
| 215 | if (rc != SQLITE_DONE) { |
| 216 | ERRMSG; |
| 217 | return rc; |
| 218 | } |
| 219 | return SQLITE_OK; |
| 220 | |
| 221 | cleanup: |
| 222 | sqlite3_finalize(stmt); |
| 223 | return rc; |
| 224 | } |
| 225 | |
| 226 | static int commitTransaction(sqlite3 *db, char* errString) |
| 227 | { |
| 228 | sqlite3_stmt *stmt; |
| 229 | int rc; |
| 230 | |
| 231 | SQLITE_CHK(SQLITE_PREPARE(db, commitTransactionSql, strlen(commitTransactionSql)+1, &stmt, NULL)); |
| 232 | |
| 233 | rc = sqlite3_step(stmt); |
| 234 | sqlite3_finalize(stmt); |
| 235 | if (rc != SQLITE_DONE) { |
| 236 | ERRMSG; |
| 237 | return rc; |
| 238 | } |
| 239 | return SQLITE_OK; |
| 240 | |
| 241 | cleanup: |
| 242 | sqlite3_finalize(stmt); |
| 243 | return rc; |
| 244 | } |
| 245 | #endif |
| 246 | |
| 247 | /** |
| 248 | * Initialize remote ZID and remote name tables. |
| 249 | * |
| 250 | * First drop the remote ZID and remote name tables and create them again. |
| 251 | * All information regarding remote peers is lost. |
| 252 | */ |
| 253 | static int initializeRemoteTables(sqlite3 *db, char* errString) |
| 254 | { |
| 255 | sqlite3_stmt * stmt; |
| 256 | int rc; |
| 257 | |
| 258 | /* First drop them, just to be on the save side |
| 259 | * Ignore errors, there is nothing to drop on empty DB. If ZrtpIdOwn was |
| 260 | * deleted using DB admin command then we need to drop the remote id table |
| 261 | * and names also to have a clean state. |
| 262 | */ |
| 263 | rc = SQLITE_PREPARE(db, dropZrtpIdRemote, strlen(dropZrtpIdRemote)+1, &stmt, NULL); |
| 264 | rc = sqlite3_step(stmt); |
| 265 | sqlite3_finalize(stmt); |
| 266 | |
| 267 | rc = SQLITE_PREPARE(db, dropZrtpNames, strlen(dropZrtpNames)+1, &stmt, NULL); |
| 268 | rc = sqlite3_step(stmt); |
| 269 | sqlite3_finalize(stmt); |
| 270 | |
| 271 | SQLITE_CHK(SQLITE_PREPARE(db, createZrtpIdRemote, strlen(createZrtpIdRemote)+1, &stmt, NULL)); |
| 272 | rc = sqlite3_step(stmt); |
| 273 | sqlite3_finalize(stmt); |
| 274 | if (rc != SQLITE_DONE) { |
| 275 | ERRMSG; |
| 276 | return rc; |
| 277 | } |
| 278 | SQLITE_CHK(SQLITE_PREPARE(db, createZrtpNames, strlen(createZrtpNames)+1, &stmt, NULL)); |
| 279 | rc = sqlite3_step(stmt); |
| 280 | sqlite3_finalize(stmt); |
| 281 | if (rc != SQLITE_DONE) { |
| 282 | ERRMSG; |
| 283 | return rc; |
| 284 | } |
| 285 | return 0; |
| 286 | |
| 287 | cleanup: |
| 288 | sqlite3_finalize(stmt); |
| 289 | return rc; |
| 290 | |
| 291 | } |
| 292 | /** |
| 293 | * Create ZRTP cache tables in database. |
| 294 | * |
| 295 | * openCache calls this function if it cannot find the table zrtpId_own. This indicates |
| 296 | * that no ZRTP cache tables are available in the database. |
| 297 | */ |
| 298 | static int createTables(sqlite3 *db, char* errString) |
| 299 | { |
| 300 | sqlite3_stmt * stmt; |
| 301 | int rc; |
| 302 | |
| 303 | /* no ZRTP cache tables were found - create them, first the OwnId table */ |
| 304 | SQLITE_CHK(SQLITE_PREPARE(db, createZrtpIdOwn, strlen(createZrtpIdOwn)+1, &stmt, NULL)); |
| 305 | |
| 306 | rc = sqlite3_step(stmt); |
| 307 | sqlite3_finalize(stmt); |
| 308 | if (rc != SQLITE_DONE) { |
| 309 | ERRMSG; |
| 310 | return rc; |
| 311 | } |
| 312 | return initializeRemoteTables(db, errString); |
| 313 | |
| 314 | cleanup: |
| 315 | sqlite3_finalize(stmt); |
| 316 | return rc; |
| 317 | } |
| 318 | |
| 319 | static int insertRemoteZidRecord(void *vdb, const uint8_t *remoteZid, const uint8_t *localZid, |
| 320 | const remoteZidRecord_t *remZid, char* errString) |
| 321 | { |
| 322 | sqlite3 *db = (sqlite3*)vdb; |
| 323 | sqlite3_stmt *stmt; |
| 324 | int rc = 0; |
| 325 | |
| 326 | char b64RemoteZid[IDENTIFIER_LEN*2] = {0}; |
| 327 | char b64LocalZid[IDENTIFIER_LEN*2] = {0}; |
| 328 | |
| 329 | /* Get B64 code for remoteZid first */ |
| 330 | b64Encode(remoteZid, IDENTIFIER_LEN, b64RemoteZid, IDENTIFIER_LEN*2); |
| 331 | |
| 332 | /* Get B64 code for localZid now */ |
| 333 | b64Encode(localZid, IDENTIFIER_LEN, b64LocalZid, IDENTIFIER_LEN*2); |
| 334 | |
| 335 | SQLITE_CHK(SQLITE_PREPARE(db, insertZrtpIdRemote, strlen(insertZrtpIdRemote)+1, &stmt, NULL)); |
| 336 | |
| 337 | /* For *_bind_* methods: column index starts with 1 (one), not zero */ |
| 338 | SQLITE_CHK(sqlite3_bind_text(stmt, 1, b64RemoteZid, strlen(b64RemoteZid), SQLITE_STATIC)); |
| 339 | SQLITE_CHK(sqlite3_bind_text(stmt, 12, b64LocalZid, strlen(b64LocalZid), SQLITE_STATIC)); |
| 340 | SQLITE_CHK(sqlite3_bind_int(stmt, 2, remZid->flags)); |
| 341 | SQLITE_CHK(sqlite3_bind_blob(stmt, 3, remZid->rs1, RS_LENGTH, SQLITE_STATIC)); |
| 342 | SQLITE_CHK(sqlite3_bind_int64(stmt, 4, remZid->rs1LastUse)); |
| 343 | SQLITE_CHK(sqlite3_bind_int64(stmt, 5, remZid->rs1Ttl)); |
| 344 | SQLITE_CHK(sqlite3_bind_blob(stmt, 6, remZid->rs2, RS_LENGTH, SQLITE_STATIC)); |
| 345 | SQLITE_CHK(sqlite3_bind_int64(stmt, 7, remZid->rs2LastUse)); |
| 346 | SQLITE_CHK(sqlite3_bind_int64(stmt, 8, remZid->rs2Ttl)); |
| 347 | SQLITE_CHK(sqlite3_bind_blob(stmt, 9, remZid->mitmKey, RS_LENGTH, SQLITE_STATIC)); |
| 348 | SQLITE_CHK(sqlite3_bind_int64(stmt, 10, remZid->mitmLastUse)); |
| 349 | SQLITE_CHK(sqlite3_bind_int64(stmt, 11, remZid->secureSince)); |
| 350 | SQLITE_CHK(sqlite3_bind_int(stmt, 13, remZid->preshCounter)); |
| 351 | |
| 352 | rc = sqlite3_step(stmt); |
| 353 | sqlite3_finalize(stmt); |
| 354 | if (rc != SQLITE_DONE) { |
| 355 | ERRMSG; |
| 356 | return rc; |
| 357 | } |
| 358 | return SQLITE_OK; |
| 359 | |
| 360 | cleanup: |
| 361 | sqlite3_finalize(stmt); |
| 362 | return rc; |
| 363 | |
| 364 | } |
| 365 | |
| 366 | static int updateRemoteZidRecord(void *vdb, const uint8_t *remoteZid, const uint8_t *localZid, |
| 367 | const remoteZidRecord_t *remZid, char* errString) |
| 368 | { |
| 369 | sqlite3 *db = (sqlite3*)vdb; |
| 370 | sqlite3_stmt *stmt; |
| 371 | int rc; |
| 372 | |
| 373 | char b64RemoteZid[IDENTIFIER_LEN*2] = {0}; |
| 374 | char b64LocalZid[IDENTIFIER_LEN*2] = {0}; |
| 375 | |
| 376 | /* Get B64 code for remoteZid first */ |
| 377 | b64Encode(remoteZid, IDENTIFIER_LEN, b64RemoteZid, IDENTIFIER_LEN*2); |
| 378 | |
| 379 | /* Get B64 code for localZid now */ |
| 380 | b64Encode(localZid, IDENTIFIER_LEN, b64LocalZid, IDENTIFIER_LEN*2); |
| 381 | |
| 382 | SQLITE_CHK(SQLITE_PREPARE(db, updateZrtpIdRemote, strlen(updateZrtpIdRemote)+1, &stmt, NULL)); |
| 383 | |
| 384 | /* For *_bind_* methods: column index starts with 1 (one), not zero */ |
| 385 | /* Select for update with the following keys */ |
| 386 | SQLITE_CHK(sqlite3_bind_text(stmt, 1, b64RemoteZid, strlen(b64RemoteZid), SQLITE_STATIC)); |
| 387 | SQLITE_CHK(sqlite3_bind_text(stmt, 12, b64LocalZid, strlen(b64LocalZid), SQLITE_STATIC)); |
| 388 | |
| 389 | /* Update the following values */ |
| 390 | SQLITE_CHK(sqlite3_bind_int(stmt, 2, remZid->flags)); |
| 391 | SQLITE_CHK(sqlite3_bind_blob(stmt, 3, remZid->rs1, RS_LENGTH, SQLITE_STATIC)); |
| 392 | SQLITE_CHK(sqlite3_bind_int64(stmt, 4, remZid->rs1LastUse)); |
| 393 | SQLITE_CHK(sqlite3_bind_int64(stmt, 5, remZid->rs1Ttl)); |
| 394 | SQLITE_CHK(sqlite3_bind_blob(stmt, 6, remZid->rs2, RS_LENGTH, SQLITE_STATIC)); |
| 395 | SQLITE_CHK(sqlite3_bind_int64(stmt, 7, remZid->rs2LastUse)); |
| 396 | SQLITE_CHK(sqlite3_bind_int64(stmt, 8, remZid->rs2Ttl)); |
| 397 | SQLITE_CHK(sqlite3_bind_blob(stmt, 9, remZid->mitmKey, RS_LENGTH, SQLITE_STATIC)); |
| 398 | SQLITE_CHK(sqlite3_bind_int64(stmt, 10, remZid->mitmLastUse)); |
| 399 | SQLITE_CHK(sqlite3_bind_int64(stmt, 11, remZid->secureSince)); |
| 400 | SQLITE_CHK(sqlite3_bind_int(stmt, 13, remZid->preshCounter)); |
| 401 | |
| 402 | rc = sqlite3_step(stmt); |
| 403 | sqlite3_finalize(stmt); |
| 404 | if (rc != SQLITE_DONE) { |
| 405 | ERRMSG; |
| 406 | return rc; |
| 407 | } |
| 408 | return SQLITE_OK; |
| 409 | |
| 410 | cleanup: |
| 411 | sqlite3_finalize(stmt); |
| 412 | return rc; |
| 413 | } |
| 414 | |
| 415 | static int readRemoteZidRecord(void *vdb, const uint8_t *remoteZid, const uint8_t *localZid, |
| 416 | remoteZidRecord_t *remZid, char* errString) |
| 417 | { |
| 418 | sqlite3 *db = (sqlite3*)vdb; |
| 419 | sqlite3_stmt *stmt; |
| 420 | int rc; |
| 421 | int found = 0; |
| 422 | |
| 423 | char b64RemoteZid[IDENTIFIER_LEN*2] = {0}; |
| 424 | char b64LocalZid[IDENTIFIER_LEN*2] = {0}; |
| 425 | |
| 426 | /* Get B64 code for remoteZid */ |
| 427 | b64Encode(remoteZid, IDENTIFIER_LEN, b64RemoteZid, IDENTIFIER_LEN*2); |
| 428 | |
| 429 | /* Get B64 code for localZid */ |
| 430 | b64Encode(localZid, IDENTIFIER_LEN, b64LocalZid, IDENTIFIER_LEN*2); |
| 431 | |
| 432 | SQLITE_CHK(SQLITE_PREPARE(db, selectZrtpIdRemoteAll, strlen(selectZrtpIdRemoteAll)+1, &stmt, NULL)); |
| 433 | SQLITE_CHK(sqlite3_bind_text(stmt, 1, b64RemoteZid, strlen(b64RemoteZid), SQLITE_STATIC)); |
| 434 | SQLITE_CHK(sqlite3_bind_text(stmt, 2, b64LocalZid, strlen(b64LocalZid), SQLITE_STATIC)); |
| 435 | |
| 436 | /* Getting data from result set: column index starts with 0 (zero), not one */ |
| 437 | while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { |
| 438 | remZid->flags = sqlite3_column_int(stmt, 0); |
| 439 | memcpy(remZid->rs1, sqlite3_column_blob(stmt, 1), RS_LENGTH); |
| 440 | remZid->rs1LastUse = sqlite3_column_int64(stmt, 2); |
| 441 | remZid->rs1Ttl = sqlite3_column_int64(stmt, 3); |
| 442 | memcpy(remZid->rs2, sqlite3_column_blob(stmt, 4), RS_LENGTH); |
| 443 | remZid->rs2LastUse = sqlite3_column_int64(stmt, 5); |
| 444 | remZid->rs2Ttl = sqlite3_column_int64(stmt, 6); |
| 445 | memcpy(remZid->mitmKey, sqlite3_column_blob(stmt, 7), RS_LENGTH); |
| 446 | remZid->mitmLastUse = sqlite3_column_int64(stmt, 8); |
| 447 | remZid->secureSince = sqlite3_column_int64(stmt, 9); |
| 448 | remZid->preshCounter = sqlite3_column_int(stmt, 10); |
| 449 | found++; |
| 450 | } |
| 451 | sqlite3_finalize(stmt); |
| 452 | |
| 453 | if (rc != SQLITE_DONE) { |
| 454 | ERRMSG; |
| 455 | return rc; |
| 456 | } |
| 457 | if (found == 0) { |
| 458 | remZid->flags = 0; |
| 459 | } |
| 460 | else if (found > 1) { |
| 461 | if (errString) |
| 462 | snprintf(errString, DB_CACHE_ERR_BUFF_SIZE, "ZRTP cache inconsistent. More than one remote ZID found: %d\n", found); |
| 463 | return 1; |
| 464 | } |
| 465 | return SQLITE_OK; |
| 466 | |
| 467 | cleanup: |
| 468 | sqlite3_finalize(stmt); |
| 469 | return rc; |
| 470 | } |
| 471 | |
| 472 | |
| 473 | static int readLocalZid(void *vdb, uint8_t *localZid, const char *accountInfo, char *errString) |
| 474 | { |
| 475 | sqlite3 *db = (sqlite3*)vdb; |
| 476 | sqlite3_stmt *stmt; |
| 477 | char *zidBase64Text; |
| 478 | int rc = 0; |
| 479 | int found = 0; |
| 480 | int type = localZidWithAccount; |
| 481 | |
| 482 | if (accountInfo == NULL || !strcmp(accountInfo, defaultAccountString)) { |
| 483 | accountInfo = defaultAccountString; |
| 484 | type = localZidStandard; |
| 485 | } |
| 486 | |
| 487 | /* Find a localZid record for this combination */ |
| 488 | SQLITE_CHK(SQLITE_PREPARE(db, selectZrtpIdOwn, strlen(selectZrtpIdOwn)+1, &stmt, NULL)); |
| 489 | |
| 490 | SQLITE_CHK(sqlite3_bind_int(stmt, 1, type)); |
| 491 | SQLITE_CHK(sqlite3_bind_text(stmt, 2, accountInfo, strlen(accountInfo), SQLITE_STATIC)); |
| 492 | |
| 493 | /* Loop over result set and count it. However, use only the localZid of first row */ |
| 494 | while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { |
| 495 | if (found == 0) { |
| 496 | zidBase64Text = (char *)sqlite3_column_text(stmt, 0); |
| 497 | b64Decode(zidBase64Text, strlen(zidBase64Text), localZid, IDENTIFIER_LEN); |
| 498 | } |
| 499 | found++; |
| 500 | } |
| 501 | sqlite3_finalize(stmt); |
| 502 | |
| 503 | if (rc != SQLITE_DONE) { |
| 504 | ERRMSG; |
| 505 | return rc; |
| 506 | } |
| 507 | /* No matching record found, create new local ZID for this combination and store in DB */ |
| 508 | if (found == 0) { |
| 509 | char b64zid[IDENTIFIER_LEN+IDENTIFIER_LEN] = {0}; |
| 510 | int b64len = 0; |
| 511 | |
| 512 | /* create a 12 byte random value, convert to base 64, insert in zrtpIdOwn table */ |
| 513 | randomZRTP(localZid, IDENTIFIER_LEN); |
| 514 | b64len = b64Encode(localZid, IDENTIFIER_LEN, b64zid, IDENTIFIER_LEN+IDENTIFIER_LEN); |
| 515 | |
| 516 | SQLITE_CHK(SQLITE_PREPARE(db, insertZrtpIdOwn, strlen(insertZrtpIdOwn)+1, &stmt, NULL)); |
| 517 | |
| 518 | SQLITE_CHK(sqlite3_bind_text(stmt, 1, b64zid, b64len, SQLITE_STATIC)); |
| 519 | SQLITE_CHK(sqlite3_bind_int(stmt, 2, type)); |
| 520 | SQLITE_CHK(sqlite3_bind_text(stmt, 3, accountInfo, strlen(accountInfo), SQLITE_STATIC)); |
| 521 | |
| 522 | rc = sqlite3_step(stmt); |
| 523 | sqlite3_finalize(stmt); |
| 524 | if (rc != SQLITE_DONE) { |
| 525 | ERRMSG; |
| 526 | return rc; |
| 527 | } |
| 528 | } |
| 529 | else if (found > 1) { |
| 530 | if (errString) |
| 531 | snprintf(errString, DB_CACHE_ERR_BUFF_SIZE, |
| 532 | "ZRTP cache inconsistent. Found %d matching local ZID for account: %s\n", found, accountInfo); |
| 533 | return 1; |
| 534 | } |
| 535 | return SQLITE_OK; |
| 536 | |
| 537 | cleanup: |
| 538 | sqlite3_finalize(stmt); |
| 539 | return rc; |
| 540 | } |
| 541 | |
| 542 | /* |
| 543 | * SQLite use the following table structure to manage some internal data |
| 544 | * |
| 545 | * CREATE TABLE sqlite_master ( |
| 546 | * type TEXT, |
| 547 | * name TEXT, |
| 548 | * tbl_name TEXT, |
| 549 | * rootpage INTEGER, |
| 550 | * sql TEXT |
| 551 | * ); |
| 552 | */ |
| 553 | |
| 554 | static int openCache(const char* name, void **vpdb, char *errString) |
| 555 | { |
| 556 | sqlite3_stmt *stmt; |
| 557 | int found = 0; |
| 558 | sqlite3 **pdb = (sqlite3**)vpdb; |
| 559 | sqlite3 *db; |
| 560 | |
| 561 | #ifdef SQLITE_USE_V2 |
| 562 | int rc = sqlite3_open_v2(name, pdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL); |
| 563 | #else |
| 564 | int rc = sqlite3_open(name, pdb); |
| 565 | #endif |
| 566 | db = *pdb; |
| 567 | if (rc) { |
| 568 | ERRMSG; |
| 569 | return(rc); |
| 570 | } |
| 571 | |
| 572 | /* check if ZRTP cache tables are already available, look if zrtpIdOwn is available */ |
| 573 | SQLITE_CHK(SQLITE_PREPARE(db, lookupTables, strlen(lookupTables)+1, &stmt, NULL)); |
| 574 | rc = sqlite3_step(stmt); |
| 575 | sqlite3_finalize(stmt); |
| 576 | |
| 577 | if (rc == SQLITE_ROW) { |
| 578 | found++; |
| 579 | } |
| 580 | else if (rc != SQLITE_DONE) { |
| 581 | ERRMSG; |
| 582 | return rc; |
| 583 | } |
| 584 | /* If table zrtpOwnId not found then we have an empty cache DB */ |
| 585 | if (found == 0) { |
| 586 | rc = createTables(db, errString); |
| 587 | if (rc) |
| 588 | return rc; |
| 589 | } |
| 590 | return SQLITE_OK; |
| 591 | |
| 592 | cleanup: |
| 593 | sqlite3_finalize(stmt); |
| 594 | return rc; |
| 595 | } |
| 596 | |
| 597 | static int closeCache(void *vdb) |
| 598 | { |
Alexandre Lision | 907ed2e | 2014-02-04 10:33:09 -0500 | [diff] [blame] | 599 | |
Alexandre Lision | 7fd5d3d | 2013-12-04 13:06:40 -0500 | [diff] [blame] | 600 | sqlite3 *db = (sqlite3*)vdb; |
| 601 | sqlite3_close(db); |
| 602 | return SQLITE_OK; |
| 603 | } |
| 604 | |
Alexandre Lision | 907ed2e | 2014-02-04 10:33:09 -0500 | [diff] [blame] | 605 | static int clearCache(void *vdb, char *errString) |
| 606 | { |
| 607 | |
| 608 | sqlite3 *db = (sqlite3*)vdb; |
| 609 | sqlite3_stmt * stmt; |
| 610 | int rc; |
| 611 | |
| 612 | rc = SQLITE_PREPARE(db, dropZrtpIdOwn, strlen(dropZrtpIdOwn)+1, &stmt, NULL); |
| 613 | rc = sqlite3_step(stmt); |
| 614 | sqlite3_finalize(stmt); |
| 615 | |
| 616 | rc = createTables(db, errString); |
| 617 | if (rc) |
| 618 | return rc; |
| 619 | return SQLITE_OK; |
| 620 | } |
| 621 | |
Alexandre Lision | 7fd5d3d | 2013-12-04 13:06:40 -0500 | [diff] [blame] | 622 | static int insertZidNameRecord(void *vdb, const uint8_t *remoteZid, const uint8_t *localZid, |
| 623 | const char *accountInfo, zidNameRecord_t *zidName, char* errString) |
| 624 | { |
| 625 | sqlite3 *db = (sqlite3*)vdb; |
| 626 | sqlite3_stmt *stmt; |
| 627 | int rc = 0; |
| 628 | char b64RemoteZid[IDENTIFIER_LEN*2] = {0}; |
| 629 | char b64LocalZid[IDENTIFIER_LEN*2] = {0}; |
| 630 | |
| 631 | if (accountInfo == NULL) { |
| 632 | accountInfo = defaultAccountString; |
| 633 | } |
| 634 | |
| 635 | /* Get B64 code for remoteZid */ |
| 636 | b64Encode(remoteZid, IDENTIFIER_LEN, b64RemoteZid, IDENTIFIER_LEN*2); |
| 637 | |
| 638 | /* Get B64 code for localZid */ |
| 639 | b64Encode(localZid, IDENTIFIER_LEN, b64LocalZid, IDENTIFIER_LEN*2); |
| 640 | |
| 641 | SQLITE_CHK(SQLITE_PREPARE(db, insertZrtpNames, strlen(insertZrtpNames)+1, &stmt, NULL)); |
| 642 | |
| 643 | /* For *_bind_* methods: column index starts with 1 (one), not zero */ |
| 644 | SQLITE_CHK(sqlite3_bind_text(stmt, 1, b64RemoteZid, strlen(b64RemoteZid), SQLITE_STATIC)); |
| 645 | SQLITE_CHK(sqlite3_bind_text(stmt, 2, b64LocalZid, strlen(b64LocalZid), SQLITE_STATIC)); |
| 646 | SQLITE_CHK(sqlite3_bind_text(stmt, 3, accountInfo, strlen(accountInfo), SQLITE_STATIC)); |
| 647 | SQLITE_CHK(sqlite3_bind_int(stmt, 4, zidName->flags)); |
| 648 | SQLITE_CHK(sqlite3_bind_int64(stmt, 5, (int64_t)time(NULL))); |
| 649 | if (zidName->name != NULL) { |
| 650 | SQLITE_CHK(sqlite3_bind_text(stmt, 6, zidName->name, strlen(zidName->name), SQLITE_STATIC)); |
| 651 | } |
| 652 | else { |
| 653 | SQLITE_CHK(sqlite3_bind_text(stmt, 6, "_NO_NAME_", 9, SQLITE_STATIC)); |
| 654 | } |
| 655 | rc = sqlite3_step(stmt); |
| 656 | sqlite3_finalize(stmt); |
| 657 | if (rc != SQLITE_DONE) { |
| 658 | ERRMSG; |
| 659 | return rc; |
| 660 | } |
| 661 | return SQLITE_OK; |
| 662 | |
| 663 | cleanup: |
| 664 | sqlite3_finalize(stmt); |
| 665 | return rc; |
| 666 | |
| 667 | } |
| 668 | |
| 669 | |
| 670 | static int updateZidNameRecord(void *vdb, const uint8_t *remoteZid, const uint8_t *localZid, |
| 671 | const char *accountInfo, zidNameRecord_t *zidName, char* errString) |
| 672 | { |
| 673 | sqlite3 *db = (sqlite3*)vdb; |
| 674 | sqlite3_stmt *stmt; |
| 675 | int rc = 0; |
| 676 | char b64RemoteZid[IDENTIFIER_LEN*2] = {0}; |
| 677 | char b64LocalZid[IDENTIFIER_LEN*2] = {0}; |
| 678 | |
| 679 | if (accountInfo == NULL) { |
| 680 | accountInfo = defaultAccountString; |
| 681 | } |
| 682 | |
| 683 | /* Get B64 code for remoteZid */ |
| 684 | b64Encode(remoteZid, IDENTIFIER_LEN, b64RemoteZid, IDENTIFIER_LEN*2); |
| 685 | |
| 686 | /* Get B64 code for localZid */ |
| 687 | b64Encode(localZid, IDENTIFIER_LEN, b64LocalZid, IDENTIFIER_LEN*2); |
| 688 | |
| 689 | SQLITE_CHK(SQLITE_PREPARE(db, updateZrtpNames, strlen(updateZrtpNames)+1, &stmt, NULL)); |
| 690 | |
| 691 | /* For *_bind_* methods: column index starts with 1 (one), not zero */ |
| 692 | /* Select for update with the following values */ |
| 693 | SQLITE_CHK(sqlite3_bind_text(stmt, 1, b64RemoteZid, strlen(b64RemoteZid), SQLITE_STATIC)); |
| 694 | SQLITE_CHK(sqlite3_bind_text(stmt, 2, b64LocalZid, strlen(b64LocalZid), SQLITE_STATIC)); |
| 695 | SQLITE_CHK(sqlite3_bind_text(stmt, 3, accountInfo, strlen(accountInfo), SQLITE_STATIC)); |
| 696 | |
| 697 | /* Update the following vaulues */ |
| 698 | SQLITE_CHK(sqlite3_bind_int(stmt, 4, zidName->flags)); |
| 699 | SQLITE_CHK(sqlite3_bind_int64(stmt, 5, (int64_t)time(NULL))); |
| 700 | if (zidName->name != NULL) { |
| 701 | SQLITE_CHK(sqlite3_bind_text(stmt, 6, zidName->name, strlen(zidName->name), SQLITE_STATIC)); |
| 702 | } |
| 703 | else { |
| 704 | SQLITE_CHK(sqlite3_bind_text(stmt, 6, "_NO_NAME_", 9, SQLITE_STATIC)); |
| 705 | } |
| 706 | rc = sqlite3_step(stmt); |
| 707 | sqlite3_finalize(stmt); |
| 708 | if (rc != SQLITE_DONE) { |
| 709 | ERRMSG; |
| 710 | return rc; |
| 711 | } |
| 712 | return SQLITE_OK; |
| 713 | |
| 714 | cleanup: |
| 715 | sqlite3_finalize(stmt); |
| 716 | return rc; |
| 717 | |
| 718 | } |
| 719 | |
| 720 | static int readZidNameRecord(void *vdb, const uint8_t *remoteZid, const uint8_t *localZid, |
| 721 | const char *accountInfo, zidNameRecord_t *zidName, char* errString) |
| 722 | { |
| 723 | sqlite3 *db = (sqlite3*)vdb; |
| 724 | sqlite3_stmt *stmt; |
| 725 | int rc; |
| 726 | int found = 0; |
| 727 | |
| 728 | char b64RemoteZid[IDENTIFIER_LEN*2] = {0}; |
| 729 | char b64LocalZid[IDENTIFIER_LEN*2] = {0}; |
| 730 | |
| 731 | if (accountInfo == NULL) { |
| 732 | accountInfo = defaultAccountString; |
| 733 | } |
| 734 | /* Get B64 code for remoteZid */ |
| 735 | b64Encode(remoteZid, IDENTIFIER_LEN, b64RemoteZid, IDENTIFIER_LEN*2); |
| 736 | |
| 737 | /* Get B64 code for localZid */ |
| 738 | b64Encode(localZid, IDENTIFIER_LEN, b64LocalZid, IDENTIFIER_LEN*2); |
| 739 | |
| 740 | SQLITE_CHK(SQLITE_PREPARE(db, selectZrtpNames, strlen(selectZrtpNames)+1, &stmt, NULL)); |
| 741 | |
| 742 | SQLITE_CHK(sqlite3_bind_text(stmt, 1, b64RemoteZid, strlen(b64RemoteZid), SQLITE_STATIC)); |
| 743 | SQLITE_CHK(sqlite3_bind_text(stmt, 2, b64LocalZid, strlen(b64LocalZid), SQLITE_STATIC)); |
| 744 | SQLITE_CHK(sqlite3_bind_text(stmt, 3, accountInfo, strlen(accountInfo), SQLITE_STATIC)); |
| 745 | |
| 746 | /* Getting data from result set: column index starts with 0 (zero), not one */ |
| 747 | while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) { |
| 748 | zidName->flags = sqlite3_column_int(stmt, 0); |
| 749 | strncpy(zidName->name, (const char*)sqlite3_column_text(stmt, 2), zidName->nameLength); |
| 750 | zidName->nameLength = sqlite3_column_bytes(stmt, 2); /* Return number of bytes in string */ |
| 751 | found++; |
| 752 | } |
| 753 | sqlite3_finalize(stmt); |
| 754 | |
| 755 | if (rc != SQLITE_DONE) { |
| 756 | ERRMSG; |
| 757 | return rc; |
| 758 | } |
| 759 | if (found == 0) |
| 760 | zidName->flags = 0; |
| 761 | else if (found > 1) { |
| 762 | if (errString) |
| 763 | snprintf(errString, DB_CACHE_ERR_BUFF_SIZE, "ZRTP name cache inconsistent. More than one ZID name found: %d\n", found); |
| 764 | return 1; |
| 765 | } |
| 766 | return SQLITE_OK; |
| 767 | |
| 768 | cleanup: |
| 769 | sqlite3_finalize(stmt); |
| 770 | return rc; |
| 771 | } |
| 772 | |
| 773 | void getDbCacheOps(dbCacheOps_t *ops) |
| 774 | { |
| 775 | ops->openCache = openCache; |
| 776 | ops->closeCache = closeCache; |
Alexandre Lision | 907ed2e | 2014-02-04 10:33:09 -0500 | [diff] [blame] | 777 | ops->cleanCache = clearCache; |
Alexandre Lision | 7fd5d3d | 2013-12-04 13:06:40 -0500 | [diff] [blame] | 778 | |
| 779 | ops->readLocalZid = readLocalZid; |
| 780 | |
| 781 | ops->readRemoteZidRecord = readRemoteZidRecord; |
| 782 | ops->updateRemoteZidRecord = updateRemoteZidRecord; |
| 783 | ops->insertRemoteZidRecord = insertRemoteZidRecord; |
| 784 | |
| 785 | ops->readZidNameRecord = readZidNameRecord; |
| 786 | ops->updateZidNameRecord = updateZidNameRecord; |
| 787 | ops->insertZidNameRecord = insertZidNameRecord; |
| 788 | } |
| 789 | |