| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 /* | |
| 5 * This file implements PKCS 11 on top of our existing security modules | |
| 6 * | |
| 7 * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. | |
| 8 * This implementation has two slots: | |
| 9 * slot 1 is our generic crypto support. It does not require login. | |
| 10 * It supports Public Key ops, and all they bulk ciphers and hashes. | |
| 11 * It can also support Private Key ops for imported Private keys. It does | |
| 12 * not have any token storage. | |
| 13 * slot 2 is our private key support. It requires a login before use. It | |
| 14 * can store Private Keys and Certs as token objects. Currently only private | |
| 15 * keys and their associated Certificates are saved on the token. | |
| 16 * | |
| 17 * In this implementation, session objects are only visible to the session | |
| 18 * that created or generated them. | |
| 19 */ | |
| 20 | |
| 21 #include "sdb.h" | |
| 22 #include "pkcs11t.h" | |
| 23 #include "seccomon.h" | |
| 24 #include <sqlite3.h> | |
| 25 #include "prthread.h" | |
| 26 #include "prio.h" | |
| 27 #include <stdio.h> | |
| 28 #include "secport.h" | |
| 29 #include "prmon.h" | |
| 30 #include "prenv.h" | |
| 31 #include "prprf.h" | |
| 32 #include "prsystem.h" /* for PR_GetDirectorySeparator() */ | |
| 33 #include <sys/stat.h> | |
| 34 #if defined(_WIN32) | |
| 35 #include <io.h> | |
| 36 #include <windows.h> | |
| 37 #elif defined(XP_UNIX) | |
| 38 #include <unistd.h> | |
| 39 #endif | |
| 40 | |
| 41 #ifdef SQLITE_UNSAFE_THREADS | |
| 42 #include "prlock.h" | |
| 43 /* | |
| 44 * SQLite can be compiled to be thread safe or not. | |
| 45 * turn on SQLITE_UNSAFE_THREADS if the OS does not support | |
| 46 * a thread safe version of sqlite. | |
| 47 */ | |
| 48 static PRLock *sqlite_lock = NULL; | |
| 49 | |
| 50 #define LOCK_SQLITE() PR_Lock(sqlite_lock); | |
| 51 #define UNLOCK_SQLITE() PR_Unlock(sqlite_lock); | |
| 52 #else | |
| 53 #define LOCK_SQLITE() | |
| 54 #define UNLOCK_SQLITE() | |
| 55 #endif | |
| 56 | |
| 57 typedef enum { | |
| 58 SDB_CERT = 1, | |
| 59 SDB_KEY = 2 | |
| 60 } sdbDataType; | |
| 61 | |
| 62 /* | |
| 63 * defines controlling how long we wait to acquire locks. | |
| 64 * | |
| 65 * SDB_SQLITE_BUSY_TIMEOUT specifies how long (in milliseconds) | |
| 66 * sqlite will wait on lock. If that timeout expires, sqlite will | |
| 67 * return SQLITE_BUSY. | |
| 68 * SDB_BUSY_RETRY_TIME specifies how many seconds the sdb_ code waits | |
| 69 * after receiving a busy before retrying. | |
| 70 * SDB_MAX_BUSY_RETRIES specifies how many times the sdb_ will retry on | |
| 71 * a busy condition. | |
| 72 * | |
| 73 * SDB_SQLITE_BUSY_TIMEOUT affects all opertions, both manual | |
| 74 * (prepare/step/reset/finalize) and automatic (sqlite3_exec()). | |
| 75 * SDB_BUSY_RETRY_TIME and SDB_MAX_BUSY_RETRIES only affect manual operations | |
| 76 * | |
| 77 * total wait time for automatic operations: | |
| 78 * 1 second (SDB_SQLITE_BUSY_TIMEOUT/1000). | |
| 79 * total wait time for manual operations: | |
| 80 * (1 second + 5 seconds) * 10 = 60 seconds. | |
| 81 * (SDB_SQLITE_BUSY_TIMEOUT/1000 + SDB_BUSY_RETRY_TIME)*SDB_MAX_BUSY_RETRIES | |
| 82 */ | |
| 83 #define SDB_SQLITE_BUSY_TIMEOUT 1000 /* milliseconds */ | |
| 84 #define SDB_BUSY_RETRY_TIME 5 /* seconds */ | |
| 85 #define SDB_MAX_BUSY_RETRIES 10 | |
| 86 | |
| 87 /* | |
| 88 * Note on use of sqlReadDB: Only one thread at a time may have an actual | |
| 89 * operation going on given sqlite3 * database. An operation is defined as | |
| 90 * the time from a sqlite3_prepare() until the sqlite3_finalize(). | |
| 91 * Multiple sqlite3 * databases can be open and have simultaneous operations | |
| 92 * going. We use the sqlXactDB for all write operations. This database | |
| 93 * is only opened when we first create a transaction and closed when the | |
| 94 * transaction is complete. sqlReadDB is open when we first opened the database | |
| 95 * and is used for all read operation. It's use is protected by a monitor. This | |
| 96 * is because an operation can span the use of FindObjectsInit() through the | |
| 97 * call to FindObjectsFinal(). In the intermediate time it is possible to call | |
| 98 * other operations like NSC_GetAttributeValue */ | |
| 99 | |
| 100 struct SDBPrivateStr { | |
| 101 char *sqlDBName; /* invariant, path to this database */ | |
| 102 sqlite3 *sqlXactDB; /* access protected by dbMon, use protected | |
| 103 * by the transaction. Current transaction db*/ | |
| 104 PRThread *sqlXactThread; /* protected by dbMon, | |
| 105 * current transaction thread */ | |
| 106 sqlite3 *sqlReadDB; /* use protected by dbMon, value invariant */ | |
| 107 PRIntervalTime lastUpdateTime; /* last time the cache was updated */ | |
| 108 PRIntervalTime updateInterval; /* how long the cache can go before it | |
| 109 * must be updated again */ | |
| 110 sdbDataType type; /* invariant, database type */ | |
| 111 char *table; /* invariant, SQL table which contains the db */ | |
| 112 char *cacheTable; /* invariant, SQL table cache of db */ | |
| 113 PRMonitor *dbMon; /* invariant, monitor to protect | |
| 114 * sqlXact* fields, and use of the sqlReadDB */ | |
| 115 }; | |
| 116 | |
| 117 typedef struct SDBPrivateStr SDBPrivate; | |
| 118 | |
| 119 /* | |
| 120 * known attributes | |
| 121 */ | |
| 122 static const CK_ATTRIBUTE_TYPE known_attributes[] = { | |
| 123 CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, | |
| 124 CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, | |
| 125 CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, | |
| 126 CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, | |
| 127 CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, | |
| 128 CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, | |
| 129 CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, | |
| 130 CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, | |
| 131 CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, | |
| 132 CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, | |
| 133 CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, | |
| 134 CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, | |
| 135 CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, | |
| 136 CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, | |
| 137 CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, | |
| 138 CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, | |
| 139 CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, | |
| 140 CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, | |
| 141 CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, | |
| 142 CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, | |
| 143 CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, | |
| 144 CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NETSCAPE_URL, CKA_NETSCAPE_EMAIL, | |
| 145 CKA_NETSCAPE_SMIME_INFO, CKA_NETSCAPE_SMIME_TIMESTAMP, | |
| 146 CKA_NETSCAPE_PKCS8_SALT, CKA_NETSCAPE_PASSWORD_CHECK, CKA_NETSCAPE_EXPIRES, | |
| 147 CKA_NETSCAPE_KRL, CKA_NETSCAPE_PQG_COUNTER, CKA_NETSCAPE_PQG_SEED, | |
| 148 CKA_NETSCAPE_PQG_H, CKA_NETSCAPE_PQG_SEED_BITS, CKA_NETSCAPE_MODULE_SPEC, | |
| 149 CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, | |
| 150 CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, | |
| 151 CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, | |
| 152 CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, | |
| 153 CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, | |
| 154 CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, | |
| 155 CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, | |
| 156 CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS | |
| 157 }; | |
| 158 | |
| 159 static int known_attributes_size= sizeof(known_attributes)/ | |
| 160 sizeof(known_attributes[0]); | |
| 161 | |
| 162 /* Magic for an explicit NULL. NOTE: ideally this should be | |
| 163 * out of band data. Since it's not completely out of band, pick | |
| 164 * a value that has no meaning to any existing PKCS #11 attributes. | |
| 165 * This value is 1) not a valid string (imbedded '\0'). 2) not a U_LONG | |
| 166 * or a normal key (too short). 3) not a bool (too long). 4) not an RSA | |
| 167 * public exponent (too many bits). | |
| 168 */ | |
| 169 const unsigned char SQLITE_EXPLICIT_NULL[] = { 0xa5, 0x0, 0x5a }; | |
| 170 #define SQLITE_EXPLICIT_NULL_LEN 3 | |
| 171 | |
| 172 /* | |
| 173 * determine when we've completed our tasks | |
| 174 */ | |
| 175 static int | |
| 176 sdb_done(int err, int *count) | |
| 177 { | |
| 178 /* allow as many rows as the database wants to give */ | |
| 179 if (err == SQLITE_ROW) { | |
| 180 *count = 0; | |
| 181 return 0; | |
| 182 } | |
| 183 if (err != SQLITE_BUSY) { | |
| 184 return 1; | |
| 185 } | |
| 186 /* err == SQLITE_BUSY, Dont' retry forever in this case */ | |
| 187 if (++(*count) >= SDB_MAX_BUSY_RETRIES) { | |
| 188 return 1; | |
| 189 } | |
| 190 return 0; | |
| 191 } | |
| 192 | |
| 193 /* | |
| 194 * find out where sqlite stores the temp tables. We do this by replicating | |
| 195 * the logic from sqlite. | |
| 196 */ | |
| 197 #if defined(_WIN32) | |
| 198 static char * | |
| 199 sdb_getFallbackTempDir(void) | |
| 200 { | |
| 201 /* sqlite uses sqlite3_temp_directory if it is not NULL. We don't have | |
| 202 * access to sqlite3_temp_directory because it is not exported from | |
| 203 * sqlite3.dll. Assume sqlite3_win32_set_directory isn't called and | |
| 204 * sqlite3_temp_directory is NULL. | |
| 205 */ | |
| 206 char path[MAX_PATH]; | |
| 207 DWORD rv; | |
| 208 size_t len; | |
| 209 | |
| 210 rv = GetTempPathA(MAX_PATH, path); | |
| 211 if (rv > MAX_PATH || rv == 0) | |
| 212 return NULL; | |
| 213 len = strlen(path); | |
| 214 if (len == 0) | |
| 215 return NULL; | |
| 216 /* The returned string ends with a backslash, for example, "C:\TEMP\". */ | |
| 217 if (path[len - 1] == '\\') | |
| 218 path[len - 1] = '\0'; | |
| 219 return PORT_Strdup(path); | |
| 220 } | |
| 221 #elif defined(XP_UNIX) | |
| 222 static char * | |
| 223 sdb_getFallbackTempDir(void) | |
| 224 { | |
| 225 const char *azDirs[] = { | |
| 226 NULL, | |
| 227 NULL, | |
| 228 "/var/tmp", | |
| 229 "/usr/tmp", | |
| 230 "/tmp", | |
| 231 NULL /* List terminator */ | |
| 232 }; | |
| 233 unsigned int i; | |
| 234 struct stat buf; | |
| 235 const char *zDir = NULL; | |
| 236 | |
| 237 azDirs[0] = sqlite3_temp_directory; | |
| 238 azDirs[1] = PR_GetEnvSecure("TMPDIR"); | |
| 239 | |
| 240 for (i = 0; i < PR_ARRAY_SIZE(azDirs); i++) { | |
| 241 zDir = azDirs[i]; | |
| 242 if (zDir == NULL) continue; | |
| 243 if (stat(zDir, &buf)) continue; | |
| 244 if (!S_ISDIR(buf.st_mode)) continue; | |
| 245 if (access(zDir, 07)) continue; | |
| 246 break; | |
| 247 } | |
| 248 | |
| 249 if (zDir == NULL) | |
| 250 return NULL; | |
| 251 return PORT_Strdup(zDir); | |
| 252 } | |
| 253 #else | |
| 254 #error "sdb_getFallbackTempDir not implemented" | |
| 255 #endif | |
| 256 | |
| 257 #ifndef SQLITE_FCNTL_TEMPFILENAME | |
| 258 /* SQLITE_FCNTL_TEMPFILENAME was added in SQLite 3.7.15 */ | |
| 259 #define SQLITE_FCNTL_TEMPFILENAME 16 | |
| 260 #endif | |
| 261 | |
| 262 static char * | |
| 263 sdb_getTempDir(sqlite3 *sqlDB) | |
| 264 { | |
| 265 int sqlrv; | |
| 266 char *result = NULL; | |
| 267 char *tempName = NULL; | |
| 268 char *foundSeparator = NULL; | |
| 269 | |
| 270 /* Obtain temporary filename in sqlite's directory for temporary tables */ | |
| 271 sqlrv = sqlite3_file_control(sqlDB, 0, SQLITE_FCNTL_TEMPFILENAME, | |
| 272 (void*)&tempName); | |
| 273 if (sqlrv == SQLITE_NOTFOUND) { | |
| 274 /* SQLITE_FCNTL_TEMPFILENAME not implemented because we are using | |
| 275 * an older SQLite. */ | |
| 276 return sdb_getFallbackTempDir(); | |
| 277 } | |
| 278 if (sqlrv != SQLITE_OK) { | |
| 279 return NULL; | |
| 280 } | |
| 281 | |
| 282 /* We'll extract the temporary directory from tempName */ | |
| 283 foundSeparator = PORT_Strrchr(tempName, PR_GetDirectorySeparator()); | |
| 284 if (foundSeparator) { | |
| 285 /* We shorten the temp filename string to contain only | |
| 286 * the directory name (including the trailing separator). | |
| 287 * We know the byte after the foundSeparator position is | |
| 288 * safe to use, in the shortest scenario it contains the | |
| 289 * end-of-string byte. | |
| 290 * By keeping the separator at the found position, it will | |
| 291 * even work if tempDir consists of the separator, only. | |
| 292 * (In this case the toplevel directory will be used for | |
| 293 * access speed testing). */ | |
| 294 ++foundSeparator; | |
| 295 *foundSeparator = 0; | |
| 296 | |
| 297 /* Now we copy the directory name for our caller */ | |
| 298 result = PORT_Strdup(tempName); | |
| 299 } | |
| 300 | |
| 301 sqlite3_free(tempName); | |
| 302 return result; | |
| 303 } | |
| 304 | |
| 305 /* | |
| 306 * Map SQL_LITE errors to PKCS #11 errors as best we can. | |
| 307 */ | |
| 308 static CK_RV | |
| 309 sdb_mapSQLError(sdbDataType type, int sqlerr) | |
| 310 { | |
| 311 switch (sqlerr) { | |
| 312 /* good matches */ | |
| 313 case SQLITE_OK: | |
| 314 case SQLITE_DONE: | |
| 315 return CKR_OK; | |
| 316 case SQLITE_NOMEM: | |
| 317 return CKR_HOST_MEMORY; | |
| 318 case SQLITE_READONLY: | |
| 319 return CKR_TOKEN_WRITE_PROTECTED; | |
| 320 /* close matches */ | |
| 321 case SQLITE_AUTH: | |
| 322 case SQLITE_PERM: | |
| 323 /*return CKR_USER_NOT_LOGGED_IN; */ | |
| 324 case SQLITE_CANTOPEN: | |
| 325 case SQLITE_NOTFOUND: | |
| 326 /* NSS distiguishes between failure to open the cert and the key db */ | |
| 327 return type == SDB_CERT ? | |
| 328 CKR_NETSCAPE_CERTDB_FAILED : CKR_NETSCAPE_KEYDB_FAILED; | |
| 329 case SQLITE_IOERR: | |
| 330 return CKR_DEVICE_ERROR; | |
| 331 default: | |
| 332 break; | |
| 333 } | |
| 334 return CKR_GENERAL_ERROR; | |
| 335 } | |
| 336 | |
| 337 | |
| 338 /* | |
| 339 * build up database name from a directory, prefix, name, version and flags. | |
| 340 */ | |
| 341 static char *sdb_BuildFileName(const char * directory, | |
| 342 const char *prefix, const char *type, | |
| 343 int version) | |
| 344 { | |
| 345 char *dbname = NULL; | |
| 346 /* build the full dbname */ | |
| 347 dbname = sqlite3_mprintf("%s%c%s%s%d.db", directory, | |
| 348 (int)(unsigned char)PR_GetDirectorySeparator(), | |
| 349 prefix, type, version); | |
| 350 return dbname; | |
| 351 } | |
| 352 | |
| 353 | |
| 354 /* | |
| 355 * find out how expensive the access system call is for non-existant files | |
| 356 * in the given directory. Return the number of operations done in 33 ms. | |
| 357 */ | |
| 358 static PRUint32 | |
| 359 sdb_measureAccess(const char *directory) | |
| 360 { | |
| 361 PRUint32 i; | |
| 362 PRIntervalTime time; | |
| 363 PRIntervalTime delta; | |
| 364 PRIntervalTime duration = PR_MillisecondsToInterval(33); | |
| 365 const char *doesntExistName = "_dOeSnotExist_.db"; | |
| 366 char *temp, *tempStartOfFilename; | |
| 367 size_t maxTempLen, maxFileNameLen, directoryLength; | |
| 368 | |
| 369 /* no directory, just return one */ | |
| 370 if (directory == NULL) { | |
| 371 return 1; | |
| 372 } | |
| 373 | |
| 374 /* our calculation assumes time is a 4 bytes == 32 bit integer */ | |
| 375 PORT_Assert(sizeof(time) == 4); | |
| 376 | |
| 377 directoryLength = strlen(directory); | |
| 378 | |
| 379 maxTempLen = directoryLength + strlen(doesntExistName) | |
| 380 + 1 /* potential additional separator char */ | |
| 381 + 11 /* max chars for 32 bit int plus potential sign */ | |
| 382 + 1; /* zero terminator */ | |
| 383 | |
| 384 temp = PORT_Alloc(maxTempLen); | |
| 385 if (!temp) { | |
| 386 return 1; | |
| 387 } | |
| 388 | |
| 389 /* We'll copy directory into temp just once, then ensure it ends | |
| 390 * with the directory separator, then remember the position after | |
| 391 * the separator, and calculate the number of remaining bytes. */ | |
| 392 | |
| 393 strcpy(temp, directory); | |
| 394 if (directory[directoryLength - 1] != PR_GetDirectorySeparator()) { | |
| 395 temp[directoryLength++] = PR_GetDirectorySeparator(); | |
| 396 } | |
| 397 tempStartOfFilename = temp + directoryLength; | |
| 398 maxFileNameLen = maxTempLen - directoryLength; | |
| 399 | |
| 400 /* measure number of Access operations that can be done in 33 milliseconds | |
| 401 * (1/30'th of a second), or 10000 operations, which ever comes first. | |
| 402 */ | |
| 403 time = PR_IntervalNow(); | |
| 404 for (i=0; i < 10000u; i++) { | |
| 405 PRIntervalTime next; | |
| 406 | |
| 407 /* We'll use the variable part first in the filename string, just in | |
| 408 * case it's longer than assumed, so if anything gets cut off, it | |
| 409 * will be cut off from the constant part. | |
| 410 * This code assumes the directory name at the beginning of | |
| 411 * temp remains unchanged during our loop. */ | |
| 412 PR_snprintf(tempStartOfFilename, maxFileNameLen, | |
| 413 ".%lu%s", (PRUint32)(time+i), doesntExistName); | |
| 414 PR_Access(temp,PR_ACCESS_EXISTS); | |
| 415 next = PR_IntervalNow(); | |
| 416 delta = next - time; | |
| 417 if (delta >= duration) | |
| 418 break; | |
| 419 } | |
| 420 | |
| 421 PORT_Free(temp); | |
| 422 | |
| 423 /* always return 1 or greater */ | |
| 424 return i ? i : 1u; | |
| 425 } | |
| 426 | |
| 427 /* | |
| 428 * some file sytems are very slow to run sqlite3 on, particularly if the | |
| 429 * access count is pretty high. On these filesystems is faster to create | |
| 430 * a temporary database on the local filesystem and access that. This | |
| 431 * code uses a temporary table to create that cache. Temp tables are | |
| 432 * automatically cleared when the database handle it was created on | |
| 433 * Is freed. | |
| 434 */ | |
| 435 static const char DROP_CACHE_CMD[] = "DROP TABLE %s"; | |
| 436 static const char CREATE_CACHE_CMD[] = | |
| 437 "CREATE TEMPORARY TABLE %s AS SELECT * FROM %s"; | |
| 438 static const char CREATE_ISSUER_INDEX_CMD[] = | |
| 439 "CREATE INDEX issuer ON %s (a81)"; | |
| 440 static const char CREATE_SUBJECT_INDEX_CMD[] = | |
| 441 "CREATE INDEX subject ON %s (a101)"; | |
| 442 static const char CREATE_LABEL_INDEX_CMD[] = "CREATE INDEX label ON %s (a3)"; | |
| 443 static const char CREATE_ID_INDEX_CMD[] = "CREATE INDEX ckaid ON %s (a102)"; | |
| 444 | |
| 445 static CK_RV | |
| 446 sdb_buildCache(sqlite3 *sqlDB, sdbDataType type, | |
| 447 const char *cacheTable, const char *table) | |
| 448 { | |
| 449 char *newStr; | |
| 450 int sqlerr = SQLITE_OK; | |
| 451 | |
| 452 newStr = sqlite3_mprintf(CREATE_CACHE_CMD, cacheTable, table); | |
| 453 if (newStr == NULL) { | |
| 454 return CKR_HOST_MEMORY; | |
| 455 } | |
| 456 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 457 sqlite3_free(newStr); | |
| 458 if (sqlerr != SQLITE_OK) { | |
| 459 return sdb_mapSQLError(type, sqlerr); | |
| 460 } | |
| 461 /* failure to create the indexes is not an issue */ | |
| 462 newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, cacheTable); | |
| 463 if (newStr == NULL) { | |
| 464 return CKR_OK; | |
| 465 } | |
| 466 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 467 sqlite3_free(newStr); | |
| 468 newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, cacheTable); | |
| 469 if (newStr == NULL) { | |
| 470 return CKR_OK; | |
| 471 } | |
| 472 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 473 sqlite3_free(newStr); | |
| 474 newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, cacheTable); | |
| 475 if (newStr == NULL) { | |
| 476 return CKR_OK; | |
| 477 } | |
| 478 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 479 sqlite3_free(newStr); | |
| 480 newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, cacheTable); | |
| 481 if (newStr == NULL) { | |
| 482 return CKR_OK; | |
| 483 } | |
| 484 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 485 sqlite3_free(newStr); | |
| 486 return CKR_OK; | |
| 487 } | |
| 488 | |
| 489 /* | |
| 490 * update the cache and the data records describing it. | |
| 491 * The cache is updated by dropping the temp database and recreating it. | |
| 492 */ | |
| 493 static CK_RV | |
| 494 sdb_updateCache(SDBPrivate *sdb_p) | |
| 495 { | |
| 496 int sqlerr = SQLITE_OK; | |
| 497 CK_RV error = CKR_OK; | |
| 498 char *newStr; | |
| 499 | |
| 500 /* drop the old table */ | |
| 501 newStr = sqlite3_mprintf(DROP_CACHE_CMD, sdb_p->cacheTable); | |
| 502 if (newStr == NULL) { | |
| 503 return CKR_HOST_MEMORY; | |
| 504 } | |
| 505 sqlerr = sqlite3_exec(sdb_p->sqlReadDB, newStr, NULL, 0, NULL); | |
| 506 sqlite3_free(newStr); | |
| 507 if ((sqlerr != SQLITE_OK) && (sqlerr != SQLITE_ERROR )) { | |
| 508 /* something went wrong with the drop, don't try to refresh... | |
| 509 * NOTE: SQLITE_ERROR is returned if the table doesn't exist. In | |
| 510 * that case, we just continue on and try to reload it */ | |
| 511 return sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 512 } | |
| 513 | |
| 514 | |
| 515 /* set up the new table */ | |
| 516 error = sdb_buildCache(sdb_p->sqlReadDB,sdb_p->type, | |
| 517 sdb_p->cacheTable,sdb_p->table ); | |
| 518 if (error == CKR_OK) { | |
| 519 /* we have a new cache! */ | |
| 520 sdb_p->lastUpdateTime = PR_IntervalNow(); | |
| 521 } | |
| 522 return error; | |
| 523 } | |
| 524 | |
| 525 /* | |
| 526 * The sharing of sqlite3 handles across threads is tricky. Older versions | |
| 527 * couldn't at all, but newer ones can under strict conditions. Basically | |
| 528 * no 2 threads can use the same handle while another thread has an open | |
| 529 * stmt running. Once the sqlite3_stmt is finalized, another thread can then | |
| 530 * use the database handle. | |
| 531 * | |
| 532 * We use monitors to protect against trying to use a database before | |
| 533 * it's sqlite3_stmt is finalized. This is preferable to the opening and | |
| 534 * closing the database each operation because there is significant overhead | |
| 535 * in the open and close. Also continually opening and closing the database | |
| 536 * defeats the cache code as the cache table is lost on close (thus | |
| 537 * requiring us to have to reinitialize the cache every operation). | |
| 538 * | |
| 539 * An execption to the shared handle is transations. All writes happen | |
| 540 * through a transaction. When we are in a transaction, we must use the | |
| 541 * same database pointer for that entire transation. In this case we save | |
| 542 * the transaction database and use it for all accesses on the transaction | |
| 543 * thread. Other threads use the common database. | |
| 544 * | |
| 545 * There can only be once active transaction on the database at a time. | |
| 546 * | |
| 547 * sdb_openDBLocal() provides us with a valid database handle for whatever | |
| 548 * state we are in (reading or in a transaction), and acquires any locks | |
| 549 * appropriate to that state. It also decides when it's time to refresh | |
| 550 * the cache before we start an operation. Any database handle returned | |
| 551 * just eventually be closed with sdb_closeDBLocal(). | |
| 552 * | |
| 553 * The table returned either points to the database's physical table, or | |
| 554 * to the cached shadow. Tranactions always return the physical table | |
| 555 * and read operations return either the physical table or the cache | |
| 556 * depending on whether or not the cache exists. | |
| 557 */ | |
| 558 static CK_RV | |
| 559 sdb_openDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB, const char **table) | |
| 560 { | |
| 561 *sqlDB = NULL; | |
| 562 | |
| 563 PR_EnterMonitor(sdb_p->dbMon); | |
| 564 | |
| 565 if (table) { | |
| 566 *table = sdb_p->table; | |
| 567 } | |
| 568 | |
| 569 /* We're in a transaction, use the transaction DB */ | |
| 570 if ((sdb_p->sqlXactDB) && (sdb_p->sqlXactThread == PR_GetCurrentThread())) { | |
| 571 *sqlDB =sdb_p->sqlXactDB; | |
| 572 /* only one thread can get here, safe to unlock */ | |
| 573 PR_ExitMonitor(sdb_p->dbMon); | |
| 574 return CKR_OK; | |
| 575 } | |
| 576 | |
| 577 /* | |
| 578 * if we are just reading from the table, we may have the table | |
| 579 * cached in a temporary table (especially if it's on a shared FS). | |
| 580 * In that case we want to see updates to the table, the the granularity | |
| 581 * is on order of human scale, not computer scale. | |
| 582 */ | |
| 583 if (table && sdb_p->cacheTable) { | |
| 584 PRIntervalTime now = PR_IntervalNow(); | |
| 585 if ((now - sdb_p->lastUpdateTime) > sdb_p->updateInterval) { | |
| 586 sdb_updateCache(sdb_p); | |
| 587 } | |
| 588 *table = sdb_p->cacheTable; | |
| 589 } | |
| 590 | |
| 591 *sqlDB = sdb_p->sqlReadDB; | |
| 592 | |
| 593 /* leave holding the lock. only one thread can actually use a given | |
| 594 * database connection at once */ | |
| 595 | |
| 596 return CKR_OK; | |
| 597 } | |
| 598 | |
| 599 /* closing the local database currenly means unlocking the monitor */ | |
| 600 static CK_RV | |
| 601 sdb_closeDBLocal(SDBPrivate *sdb_p, sqlite3 *sqlDB) | |
| 602 { | |
| 603 if (sdb_p->sqlXactDB != sqlDB) { | |
| 604 /* if we weren't in a transaction, we got a lock */ | |
| 605 PR_ExitMonitor(sdb_p->dbMon); | |
| 606 } | |
| 607 return CKR_OK; | |
| 608 } | |
| 609 | |
| 610 | |
| 611 /* | |
| 612 * wrapper to sqlite3_open which also sets the busy_timeout | |
| 613 */ | |
| 614 static int | |
| 615 sdb_openDB(const char *name, sqlite3 **sqlDB, int flags) | |
| 616 { | |
| 617 int sqlerr; | |
| 618 /* | |
| 619 * in sqlite3 3.5.0, there is a new open call that allows us | |
| 620 * to specify read only. Most new OS's are still on 3.3.x (including | |
| 621 * NSS's internal version and the version shipped with Firefox). | |
| 622 */ | |
| 623 *sqlDB = NULL; | |
| 624 sqlerr = sqlite3_open(name, sqlDB); | |
| 625 if (sqlerr != SQLITE_OK) { | |
| 626 return sqlerr; | |
| 627 } | |
| 628 | |
| 629 sqlerr = sqlite3_busy_timeout(*sqlDB, SDB_SQLITE_BUSY_TIMEOUT); | |
| 630 if (sqlerr != SQLITE_OK) { | |
| 631 sqlite3_close(*sqlDB); | |
| 632 *sqlDB = NULL; | |
| 633 return sqlerr; | |
| 634 } | |
| 635 return SQLITE_OK; | |
| 636 } | |
| 637 | |
| 638 /* Sigh, if we created a new table since we opened the database, | |
| 639 * the database handle will not see the new table, we need to close this | |
| 640 * database and reopen it. Caller must be in a transaction or holding | |
| 641 * the dbMon. sqlDB is changed on success. */ | |
| 642 static int | |
| 643 sdb_reopenDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB) { | |
| 644 sqlite3 *newDB; | |
| 645 int sqlerr; | |
| 646 | |
| 647 /* open a new database */ | |
| 648 sqlerr = sdb_openDB(sdb_p->sqlDBName, &newDB, SDB_RDONLY); | |
| 649 if (sqlerr != SQLITE_OK) { | |
| 650 return sqlerr; | |
| 651 } | |
| 652 | |
| 653 /* if we are in a transaction, we may not be holding the monitor. | |
| 654 * grab it before we update the transaction database. This is | |
| 655 * safe since are using monitors. */ | |
| 656 PR_EnterMonitor(sdb_p->dbMon); | |
| 657 /* update our view of the database */ | |
| 658 if (sdb_p->sqlReadDB == *sqlDB) { | |
| 659 sdb_p->sqlReadDB = newDB; | |
| 660 } else if (sdb_p->sqlXactDB == *sqlDB) { | |
| 661 sdb_p->sqlXactDB = newDB; | |
| 662 } | |
| 663 PR_ExitMonitor(sdb_p->dbMon); | |
| 664 | |
| 665 /* close the old one */ | |
| 666 sqlite3_close(*sqlDB); | |
| 667 | |
| 668 *sqlDB = newDB; | |
| 669 return SQLITE_OK; | |
| 670 } | |
| 671 | |
| 672 struct SDBFindStr { | |
| 673 sqlite3 *sqlDB; | |
| 674 sqlite3_stmt *findstmt; | |
| 675 }; | |
| 676 | |
| 677 | |
| 678 static const char FIND_OBJECTS_CMD[] = "SELECT ALL * FROM %s WHERE %s;"; | |
| 679 static const char FIND_OBJECTS_ALL_CMD[] = "SELECT ALL * FROM %s;"; | |
| 680 CK_RV | |
| 681 sdb_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *template, CK_ULONG count, | |
| 682 SDBFind **find) | |
| 683 { | |
| 684 SDBPrivate *sdb_p = sdb->private; | |
| 685 sqlite3 *sqlDB = NULL; | |
| 686 const char *table; | |
| 687 char *newStr, *findStr = NULL; | |
| 688 sqlite3_stmt *findstmt = NULL; | |
| 689 char *join=""; | |
| 690 int sqlerr = SQLITE_OK; | |
| 691 CK_RV error = CKR_OK; | |
| 692 unsigned int i; | |
| 693 | |
| 694 LOCK_SQLITE() | |
| 695 *find = NULL; | |
| 696 error = sdb_openDBLocal(sdb_p, &sqlDB, &table); | |
| 697 if (error != CKR_OK) { | |
| 698 goto loser; | |
| 699 } | |
| 700 | |
| 701 findStr = sqlite3_mprintf(""); | |
| 702 for (i=0; findStr && i < count; i++) { | |
| 703 newStr = sqlite3_mprintf("%s%sa%x=$DATA%d", findStr, join, | |
| 704 template[i].type, i); | |
| 705 join=" AND "; | |
| 706 sqlite3_free(findStr); | |
| 707 findStr = newStr; | |
| 708 } | |
| 709 | |
| 710 if (findStr == NULL) { | |
| 711 error = CKR_HOST_MEMORY; | |
| 712 goto loser; | |
| 713 } | |
| 714 | |
| 715 if (count == 0) { | |
| 716 newStr = sqlite3_mprintf(FIND_OBJECTS_ALL_CMD, table); | |
| 717 } else { | |
| 718 newStr = sqlite3_mprintf(FIND_OBJECTS_CMD, table, findStr); | |
| 719 } | |
| 720 sqlite3_free(findStr); | |
| 721 if (newStr == NULL) { | |
| 722 error = CKR_HOST_MEMORY; | |
| 723 goto loser; | |
| 724 } | |
| 725 sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &findstmt, NULL); | |
| 726 sqlite3_free(newStr); | |
| 727 for (i=0; sqlerr == SQLITE_OK && i < count; i++) { | |
| 728 const void *blobData = template[i].pValue; | |
| 729 unsigned int blobSize = template[i].ulValueLen; | |
| 730 if (blobSize == 0) { | |
| 731 blobSize = SQLITE_EXPLICIT_NULL_LEN; | |
| 732 blobData = SQLITE_EXPLICIT_NULL; | |
| 733 } | |
| 734 sqlerr = sqlite3_bind_blob(findstmt, i+1, blobData, blobSize, | |
| 735 SQLITE_TRANSIENT); | |
| 736 } | |
| 737 if (sqlerr == SQLITE_OK) { | |
| 738 *find = PORT_New(SDBFind); | |
| 739 if (*find == NULL) { | |
| 740 error = CKR_HOST_MEMORY; | |
| 741 goto loser; | |
| 742 } | |
| 743 (*find)->findstmt = findstmt; | |
| 744 (*find)->sqlDB = sqlDB; | |
| 745 UNLOCK_SQLITE() | |
| 746 return CKR_OK; | |
| 747 } | |
| 748 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 749 | |
| 750 loser: | |
| 751 if (findstmt) { | |
| 752 sqlite3_reset(findstmt); | |
| 753 sqlite3_finalize(findstmt); | |
| 754 } | |
| 755 if (sqlDB) { | |
| 756 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 757 } | |
| 758 UNLOCK_SQLITE() | |
| 759 return error; | |
| 760 } | |
| 761 | |
| 762 | |
| 763 CK_RV | |
| 764 sdb_FindObjects(SDB *sdb, SDBFind *sdbFind, CK_OBJECT_HANDLE *object, | |
| 765 CK_ULONG arraySize, CK_ULONG *count) | |
| 766 { | |
| 767 SDBPrivate *sdb_p = sdb->private; | |
| 768 sqlite3_stmt *stmt = sdbFind->findstmt; | |
| 769 int sqlerr = SQLITE_OK; | |
| 770 int retry = 0; | |
| 771 | |
| 772 *count = 0; | |
| 773 | |
| 774 if (arraySize == 0) { | |
| 775 return CKR_OK; | |
| 776 } | |
| 777 LOCK_SQLITE() | |
| 778 | |
| 779 do { | |
| 780 sqlerr = sqlite3_step(stmt); | |
| 781 if (sqlerr == SQLITE_BUSY) { | |
| 782 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 783 } | |
| 784 if (sqlerr == SQLITE_ROW) { | |
| 785 /* only care about the id */ | |
| 786 *object++= sqlite3_column_int(stmt, 0); | |
| 787 arraySize--; | |
| 788 (*count)++; | |
| 789 } | |
| 790 } while (!sdb_done(sqlerr,&retry) && (arraySize > 0)); | |
| 791 | |
| 792 /* we only have some of the objects, there is probably more, | |
| 793 * set the sqlerr to an OK value so we return CKR_OK */ | |
| 794 if (sqlerr == SQLITE_ROW && arraySize == 0) { | |
| 795 sqlerr = SQLITE_DONE; | |
| 796 } | |
| 797 UNLOCK_SQLITE() | |
| 798 | |
| 799 return sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 800 } | |
| 801 | |
| 802 CK_RV | |
| 803 sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind) | |
| 804 { | |
| 805 SDBPrivate *sdb_p = sdb->private; | |
| 806 sqlite3_stmt *stmt = sdbFind->findstmt; | |
| 807 sqlite3 *sqlDB = sdbFind->sqlDB; | |
| 808 int sqlerr = SQLITE_OK; | |
| 809 | |
| 810 LOCK_SQLITE() | |
| 811 if (stmt) { | |
| 812 sqlite3_reset(stmt); | |
| 813 sqlerr = sqlite3_finalize(stmt); | |
| 814 } | |
| 815 if (sqlDB) { | |
| 816 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 817 } | |
| 818 PORT_Free(sdbFind); | |
| 819 | |
| 820 UNLOCK_SQLITE() | |
| 821 return sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 822 } | |
| 823 | |
| 824 static const char GET_ATTRIBUTE_CMD[] = "SELECT ALL %s FROM %s WHERE id=$ID;"; | |
| 825 CK_RV | |
| 826 sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id, | |
| 827 CK_ATTRIBUTE *template, CK_ULONG count) | |
| 828 { | |
| 829 SDBPrivate *sdb_p = sdb->private; | |
| 830 sqlite3 *sqlDB = NULL; | |
| 831 sqlite3_stmt *stmt = NULL; | |
| 832 char *getStr = NULL; | |
| 833 char *newStr = NULL; | |
| 834 const char *table = NULL; | |
| 835 int sqlerr = SQLITE_OK; | |
| 836 CK_RV error = CKR_OK; | |
| 837 int found = 0; | |
| 838 int retry = 0; | |
| 839 unsigned int i; | |
| 840 | |
| 841 | |
| 842 /* open a new db if necessary */ | |
| 843 error = sdb_openDBLocal(sdb_p, &sqlDB, &table); | |
| 844 if (error != CKR_OK) { | |
| 845 goto loser; | |
| 846 } | |
| 847 | |
| 848 for (i=0; i < count; i++) { | |
| 849 getStr = sqlite3_mprintf("a%x", template[i].type); | |
| 850 | |
| 851 if (getStr == NULL) { | |
| 852 error = CKR_HOST_MEMORY; | |
| 853 goto loser; | |
| 854 } | |
| 855 | |
| 856 newStr = sqlite3_mprintf(GET_ATTRIBUTE_CMD, getStr, table); | |
| 857 sqlite3_free(getStr); | |
| 858 getStr = NULL; | |
| 859 if (newStr == NULL) { | |
| 860 error = CKR_HOST_MEMORY; | |
| 861 goto loser; | |
| 862 } | |
| 863 | |
| 864 sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); | |
| 865 sqlite3_free(newStr); | |
| 866 newStr = NULL; | |
| 867 if (sqlerr == SQLITE_ERROR) { | |
| 868 template[i].ulValueLen = -1; | |
| 869 error = CKR_ATTRIBUTE_TYPE_INVALID; | |
| 870 continue; | |
| 871 } else if (sqlerr != SQLITE_OK) { goto loser; } | |
| 872 | |
| 873 sqlerr = sqlite3_bind_int(stmt, 1, object_id); | |
| 874 if (sqlerr != SQLITE_OK) { goto loser; } | |
| 875 | |
| 876 do { | |
| 877 sqlerr = sqlite3_step(stmt); | |
| 878 if (sqlerr == SQLITE_BUSY) { | |
| 879 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 880 } | |
| 881 if (sqlerr == SQLITE_ROW) { | |
| 882 unsigned int blobSize; | |
| 883 const char *blobData; | |
| 884 | |
| 885 blobSize = sqlite3_column_bytes(stmt, 0); | |
| 886 blobData = sqlite3_column_blob(stmt, 0); | |
| 887 if (blobData == NULL) { | |
| 888 template[i].ulValueLen = -1; | |
| 889 error = CKR_ATTRIBUTE_TYPE_INVALID; | |
| 890 break; | |
| 891 } | |
| 892 /* If the blob equals our explicit NULL value, then the | |
| 893 * attribute is a NULL. */ | |
| 894 if ((blobSize == SQLITE_EXPLICIT_NULL_LEN) && | |
| 895 (PORT_Memcmp(blobData, SQLITE_EXPLICIT_NULL, | |
| 896 SQLITE_EXPLICIT_NULL_LEN) == 0)) { | |
| 897 blobSize = 0; | |
| 898 } | |
| 899 if (template[i].pValue) { | |
| 900 if (template[i].ulValueLen < blobSize) { | |
| 901 template[i].ulValueLen = -1; | |
| 902 error = CKR_BUFFER_TOO_SMALL; | |
| 903 break; | |
| 904 } | |
| 905 PORT_Memcpy(template[i].pValue, blobData, blobSize); | |
| 906 } | |
| 907 template[i].ulValueLen = blobSize; | |
| 908 found = 1; | |
| 909 } | |
| 910 } while (!sdb_done(sqlerr,&retry)); | |
| 911 sqlite3_reset(stmt); | |
| 912 sqlite3_finalize(stmt); | |
| 913 stmt = NULL; | |
| 914 } | |
| 915 | |
| 916 loser: | |
| 917 /* fix up the error if necessary */ | |
| 918 if (error == CKR_OK) { | |
| 919 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 920 if (!found && error == CKR_OK) { | |
| 921 error = CKR_OBJECT_HANDLE_INVALID; | |
| 922 } | |
| 923 } | |
| 924 | |
| 925 if (stmt) { | |
| 926 sqlite3_reset(stmt); | |
| 927 sqlite3_finalize(stmt); | |
| 928 } | |
| 929 | |
| 930 /* if we had to open a new database, free it now */ | |
| 931 if (sqlDB) { | |
| 932 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 933 } | |
| 934 return error; | |
| 935 } | |
| 936 | |
| 937 CK_RV | |
| 938 sdb_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, | |
| 939 CK_ATTRIBUTE *template, CK_ULONG count) | |
| 940 { | |
| 941 CK_RV crv; | |
| 942 | |
| 943 if (count == 0) { | |
| 944 return CKR_OK; | |
| 945 } | |
| 946 | |
| 947 LOCK_SQLITE() | |
| 948 crv = sdb_GetAttributeValueNoLock(sdb, object_id, template, count); | |
| 949 UNLOCK_SQLITE() | |
| 950 return crv; | |
| 951 } | |
| 952 | |
| 953 static const char SET_ATTRIBUTE_CMD[] = "UPDATE %s SET %s WHERE id=$ID;"; | |
| 954 CK_RV | |
| 955 sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, | |
| 956 const CK_ATTRIBUTE *template, CK_ULONG count) | |
| 957 { | |
| 958 SDBPrivate *sdb_p = sdb->private; | |
| 959 sqlite3 *sqlDB = NULL; | |
| 960 sqlite3_stmt *stmt = NULL; | |
| 961 char *setStr = NULL; | |
| 962 char *newStr = NULL; | |
| 963 int sqlerr = SQLITE_OK; | |
| 964 int retry = 0; | |
| 965 CK_RV error = CKR_OK; | |
| 966 unsigned int i; | |
| 967 | |
| 968 if ((sdb->sdb_flags & SDB_RDONLY) != 0) { | |
| 969 return CKR_TOKEN_WRITE_PROTECTED; | |
| 970 } | |
| 971 | |
| 972 if (count == 0) { | |
| 973 return CKR_OK; | |
| 974 } | |
| 975 | |
| 976 LOCK_SQLITE() | |
| 977 setStr = sqlite3_mprintf(""); | |
| 978 for (i=0; setStr && i < count; i++) { | |
| 979 if (i==0) { | |
| 980 sqlite3_free(setStr); | |
| 981 setStr = sqlite3_mprintf("a%x=$VALUE%d", | |
| 982 template[i].type, i); | |
| 983 continue; | |
| 984 } | |
| 985 newStr = sqlite3_mprintf("%s,a%x=$VALUE%d", setStr, | |
| 986 template[i].type, i); | |
| 987 sqlite3_free(setStr); | |
| 988 setStr = newStr; | |
| 989 } | |
| 990 newStr = NULL; | |
| 991 | |
| 992 if (setStr == NULL) { | |
| 993 return CKR_HOST_MEMORY; | |
| 994 } | |
| 995 newStr = sqlite3_mprintf(SET_ATTRIBUTE_CMD, sdb_p->table, setStr); | |
| 996 sqlite3_free(setStr); | |
| 997 if (newStr == NULL) { | |
| 998 UNLOCK_SQLITE() | |
| 999 return CKR_HOST_MEMORY; | |
| 1000 } | |
| 1001 error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); | |
| 1002 if (error != CKR_OK) { | |
| 1003 goto loser; | |
| 1004 } | |
| 1005 sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); | |
| 1006 if (sqlerr != SQLITE_OK) goto loser; | |
| 1007 for (i=0; i < count; i++) { | |
| 1008 if (template[i].ulValueLen != 0) { | |
| 1009 sqlerr = sqlite3_bind_blob(stmt, i+1, template[i].pValue, | |
| 1010 template[i].ulValueLen, SQLITE_STATIC); | |
| 1011 } else { | |
| 1012 sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL, | |
| 1013 SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); | |
| 1014 } | |
| 1015 if (sqlerr != SQLITE_OK) goto loser; | |
| 1016 } | |
| 1017 sqlerr = sqlite3_bind_int(stmt, i+1, object_id); | |
| 1018 if (sqlerr != SQLITE_OK) goto loser; | |
| 1019 | |
| 1020 do { | |
| 1021 sqlerr = sqlite3_step(stmt); | |
| 1022 if (sqlerr == SQLITE_BUSY) { | |
| 1023 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 1024 } | |
| 1025 } while (!sdb_done(sqlerr,&retry)); | |
| 1026 | |
| 1027 loser: | |
| 1028 if (newStr) { | |
| 1029 sqlite3_free(newStr); | |
| 1030 } | |
| 1031 if (error == CKR_OK) { | |
| 1032 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1033 } | |
| 1034 | |
| 1035 if (stmt) { | |
| 1036 sqlite3_reset(stmt); | |
| 1037 sqlite3_finalize(stmt); | |
| 1038 } | |
| 1039 | |
| 1040 if (sqlDB) { | |
| 1041 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 1042 } | |
| 1043 | |
| 1044 UNLOCK_SQLITE() | |
| 1045 return error; | |
| 1046 } | |
| 1047 | |
| 1048 /* | |
| 1049 * check to see if a candidate object handle already exists. | |
| 1050 */ | |
| 1051 static PRBool | |
| 1052 sdb_objectExists(SDB *sdb, CK_OBJECT_HANDLE candidate) | |
| 1053 { | |
| 1054 CK_RV crv; | |
| 1055 CK_ATTRIBUTE template = { CKA_LABEL, NULL, 0 }; | |
| 1056 | |
| 1057 crv = sdb_GetAttributeValueNoLock(sdb,candidate,&template, 1); | |
| 1058 if (crv == CKR_OBJECT_HANDLE_INVALID) { | |
| 1059 return PR_FALSE; | |
| 1060 } | |
| 1061 return PR_TRUE; | |
| 1062 } | |
| 1063 | |
| 1064 /* | |
| 1065 * if we're here, we are in a transaction, so it's safe | |
| 1066 * to examine the current state of the database | |
| 1067 */ | |
| 1068 static CK_OBJECT_HANDLE | |
| 1069 sdb_getObjectId(SDB *sdb) | |
| 1070 { | |
| 1071 CK_OBJECT_HANDLE candidate; | |
| 1072 static CK_OBJECT_HANDLE next_obj = CK_INVALID_HANDLE; | |
| 1073 int count; | |
| 1074 /* | |
| 1075 * get an initial object handle to use | |
| 1076 */ | |
| 1077 if (next_obj == CK_INVALID_HANDLE) { | |
| 1078 PRTime time; | |
| 1079 time = PR_Now(); | |
| 1080 | |
| 1081 next_obj = (CK_OBJECT_HANDLE)(time & 0x3fffffffL); | |
| 1082 } | |
| 1083 candidate = next_obj++; | |
| 1084 /* detect that we've looped through all the handles... */ | |
| 1085 for (count = 0; count < 0x40000000; count++, candidate = next_obj++) { | |
| 1086 /* mask off excess bits */ | |
| 1087 candidate &= 0x3fffffff; | |
| 1088 /* if we hit zero, go to the next entry */ | |
| 1089 if (candidate == CK_INVALID_HANDLE) { | |
| 1090 continue; | |
| 1091 } | |
| 1092 /* make sure we aren't already using */ | |
| 1093 if (!sdb_objectExists(sdb, candidate)) { | |
| 1094 /* this one is free */ | |
| 1095 return candidate; | |
| 1096 } | |
| 1097 } | |
| 1098 | |
| 1099 /* no handle is free, fail */ | |
| 1100 return CK_INVALID_HANDLE; | |
| 1101 } | |
| 1102 | |
| 1103 static const char CREATE_CMD[] = "INSERT INTO %s (id%s) VALUES($ID%s);"; | |
| 1104 CK_RV | |
| 1105 sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id, | |
| 1106 const CK_ATTRIBUTE *template, CK_ULONG count) | |
| 1107 { | |
| 1108 SDBPrivate *sdb_p = sdb->private; | |
| 1109 sqlite3 *sqlDB = NULL; | |
| 1110 sqlite3_stmt *stmt = NULL; | |
| 1111 char *columnStr = NULL; | |
| 1112 char *valueStr = NULL; | |
| 1113 char *newStr = NULL; | |
| 1114 int sqlerr = SQLITE_OK; | |
| 1115 CK_RV error = CKR_OK; | |
| 1116 CK_OBJECT_HANDLE this_object = CK_INVALID_HANDLE; | |
| 1117 int retry = 0; | |
| 1118 unsigned int i; | |
| 1119 | |
| 1120 if ((sdb->sdb_flags & SDB_RDONLY) != 0) { | |
| 1121 return CKR_TOKEN_WRITE_PROTECTED; | |
| 1122 } | |
| 1123 | |
| 1124 LOCK_SQLITE() | |
| 1125 if ((*object_id != CK_INVALID_HANDLE) && | |
| 1126 !sdb_objectExists(sdb, *object_id)) { | |
| 1127 this_object = *object_id; | |
| 1128 } else { | |
| 1129 this_object = sdb_getObjectId(sdb); | |
| 1130 } | |
| 1131 if (this_object == CK_INVALID_HANDLE) { | |
| 1132 UNLOCK_SQLITE(); | |
| 1133 return CKR_HOST_MEMORY; | |
| 1134 } | |
| 1135 columnStr = sqlite3_mprintf(""); | |
| 1136 valueStr = sqlite3_mprintf(""); | |
| 1137 *object_id = this_object; | |
| 1138 for (i=0; columnStr && valueStr && i < count; i++) { | |
| 1139 newStr = sqlite3_mprintf("%s,a%x", columnStr, template[i].type); | |
| 1140 sqlite3_free(columnStr); | |
| 1141 columnStr = newStr; | |
| 1142 newStr = sqlite3_mprintf("%s,$VALUE%d", valueStr, i); | |
| 1143 sqlite3_free(valueStr); | |
| 1144 valueStr = newStr; | |
| 1145 } | |
| 1146 newStr = NULL; | |
| 1147 if ((columnStr == NULL) || (valueStr == NULL)) { | |
| 1148 if (columnStr) { | |
| 1149 sqlite3_free(columnStr); | |
| 1150 } | |
| 1151 if (valueStr) { | |
| 1152 sqlite3_free(valueStr); | |
| 1153 } | |
| 1154 UNLOCK_SQLITE() | |
| 1155 return CKR_HOST_MEMORY; | |
| 1156 } | |
| 1157 newStr = sqlite3_mprintf(CREATE_CMD, sdb_p->table, columnStr, valueStr); | |
| 1158 sqlite3_free(columnStr); | |
| 1159 sqlite3_free(valueStr); | |
| 1160 error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); | |
| 1161 if (error != CKR_OK) { | |
| 1162 goto loser; | |
| 1163 } | |
| 1164 sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); | |
| 1165 if (sqlerr != SQLITE_OK) goto loser; | |
| 1166 sqlerr = sqlite3_bind_int(stmt, 1, *object_id); | |
| 1167 if (sqlerr != SQLITE_OK) goto loser; | |
| 1168 for (i=0; i < count; i++) { | |
| 1169 if (template[i].ulValueLen) { | |
| 1170 sqlerr = sqlite3_bind_blob(stmt, i+2, template[i].pValue, | |
| 1171 template[i].ulValueLen, SQLITE_STATIC); | |
| 1172 } else { | |
| 1173 sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL, | |
| 1174 SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); | |
| 1175 } | |
| 1176 if (sqlerr != SQLITE_OK) goto loser; | |
| 1177 } | |
| 1178 | |
| 1179 do { | |
| 1180 sqlerr = sqlite3_step(stmt); | |
| 1181 if (sqlerr == SQLITE_BUSY) { | |
| 1182 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 1183 } | |
| 1184 } while (!sdb_done(sqlerr,&retry)); | |
| 1185 | |
| 1186 loser: | |
| 1187 if (newStr) { | |
| 1188 sqlite3_free(newStr); | |
| 1189 } | |
| 1190 if (error == CKR_OK) { | |
| 1191 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1192 } | |
| 1193 | |
| 1194 if (stmt) { | |
| 1195 sqlite3_reset(stmt); | |
| 1196 sqlite3_finalize(stmt); | |
| 1197 } | |
| 1198 | |
| 1199 if (sqlDB) { | |
| 1200 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 1201 } | |
| 1202 UNLOCK_SQLITE() | |
| 1203 | |
| 1204 return error; | |
| 1205 } | |
| 1206 | |
| 1207 static const char DESTROY_CMD[] = "DELETE FROM %s WHERE (id=$ID);"; | |
| 1208 CK_RV | |
| 1209 sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id) | |
| 1210 { | |
| 1211 SDBPrivate *sdb_p = sdb->private; | |
| 1212 sqlite3 *sqlDB = NULL; | |
| 1213 sqlite3_stmt *stmt = NULL; | |
| 1214 char *newStr = NULL; | |
| 1215 int sqlerr = SQLITE_OK; | |
| 1216 CK_RV error = CKR_OK; | |
| 1217 int retry = 0; | |
| 1218 | |
| 1219 if ((sdb->sdb_flags & SDB_RDONLY) != 0) { | |
| 1220 return CKR_TOKEN_WRITE_PROTECTED; | |
| 1221 } | |
| 1222 | |
| 1223 LOCK_SQLITE() | |
| 1224 error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); | |
| 1225 if (error != CKR_OK) { | |
| 1226 goto loser; | |
| 1227 } | |
| 1228 newStr = sqlite3_mprintf(DESTROY_CMD, sdb_p->table); | |
| 1229 if (newStr == NULL) { | |
| 1230 error = CKR_HOST_MEMORY; | |
| 1231 goto loser; | |
| 1232 } | |
| 1233 sqlerr =sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); | |
| 1234 sqlite3_free(newStr); | |
| 1235 if (sqlerr != SQLITE_OK) goto loser; | |
| 1236 sqlerr =sqlite3_bind_int(stmt, 1, object_id); | |
| 1237 if (sqlerr != SQLITE_OK) goto loser; | |
| 1238 | |
| 1239 do { | |
| 1240 sqlerr = sqlite3_step(stmt); | |
| 1241 if (sqlerr == SQLITE_BUSY) { | |
| 1242 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 1243 } | |
| 1244 } while (!sdb_done(sqlerr,&retry)); | |
| 1245 | |
| 1246 loser: | |
| 1247 if (error == CKR_OK) { | |
| 1248 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1249 } | |
| 1250 | |
| 1251 if (stmt) { | |
| 1252 sqlite3_reset(stmt); | |
| 1253 sqlite3_finalize(stmt); | |
| 1254 } | |
| 1255 | |
| 1256 if (sqlDB) { | |
| 1257 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 1258 } | |
| 1259 | |
| 1260 UNLOCK_SQLITE() | |
| 1261 return error; | |
| 1262 } | |
| 1263 | |
| 1264 static const char BEGIN_CMD[] = "BEGIN IMMEDIATE TRANSACTION;"; | |
| 1265 /* | |
| 1266 * start a transaction. | |
| 1267 * | |
| 1268 * We need to open a new database, then store that new database into | |
| 1269 * the private data structure. We open the database first, then use locks | |
| 1270 * to protect storing the data to prevent deadlocks. | |
| 1271 */ | |
| 1272 CK_RV | |
| 1273 sdb_Begin(SDB *sdb) | |
| 1274 { | |
| 1275 SDBPrivate *sdb_p = sdb->private; | |
| 1276 sqlite3 *sqlDB = NULL; | |
| 1277 sqlite3_stmt *stmt = NULL; | |
| 1278 int sqlerr = SQLITE_OK; | |
| 1279 CK_RV error = CKR_OK; | |
| 1280 int retry = 0; | |
| 1281 | |
| 1282 | |
| 1283 if ((sdb->sdb_flags & SDB_RDONLY) != 0) { | |
| 1284 return CKR_TOKEN_WRITE_PROTECTED; | |
| 1285 } | |
| 1286 | |
| 1287 | |
| 1288 LOCK_SQLITE() | |
| 1289 | |
| 1290 /* get a new version that we will use for the entire transaction */ | |
| 1291 sqlerr = sdb_openDB(sdb_p->sqlDBName, &sqlDB, SDB_RDWR); | |
| 1292 if (sqlerr != SQLITE_OK) { | |
| 1293 goto loser; | |
| 1294 } | |
| 1295 | |
| 1296 sqlerr =sqlite3_prepare_v2(sqlDB, BEGIN_CMD, -1, &stmt, NULL); | |
| 1297 | |
| 1298 do { | |
| 1299 sqlerr = sqlite3_step(stmt); | |
| 1300 if (sqlerr == SQLITE_BUSY) { | |
| 1301 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 1302 } | |
| 1303 } while (!sdb_done(sqlerr,&retry)); | |
| 1304 | |
| 1305 if (stmt) { | |
| 1306 sqlite3_reset(stmt); | |
| 1307 sqlite3_finalize(stmt); | |
| 1308 } | |
| 1309 | |
| 1310 loser: | |
| 1311 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1312 | |
| 1313 /* we are starting a new transaction, | |
| 1314 * and if we succeeded, then save this database for the rest of | |
| 1315 * our transaction */ | |
| 1316 if (error == CKR_OK) { | |
| 1317 /* we hold a 'BEGIN TRANSACTION' and a sdb_p->lock. At this point | |
| 1318 * sdb_p->sqlXactDB MUST be null */ | |
| 1319 PR_EnterMonitor(sdb_p->dbMon); | |
| 1320 PORT_Assert(sdb_p->sqlXactDB == NULL); | |
| 1321 sdb_p->sqlXactDB = sqlDB; | |
| 1322 sdb_p->sqlXactThread = PR_GetCurrentThread(); | |
| 1323 PR_ExitMonitor(sdb_p->dbMon); | |
| 1324 } else { | |
| 1325 /* we failed to start our transaction, | |
| 1326 * free any databases we opened. */ | |
| 1327 if (sqlDB) { | |
| 1328 sqlite3_close(sqlDB); | |
| 1329 } | |
| 1330 } | |
| 1331 | |
| 1332 UNLOCK_SQLITE() | |
| 1333 return error; | |
| 1334 } | |
| 1335 | |
| 1336 /* | |
| 1337 * Complete a transaction. Basically undo everything we did in begin. | |
| 1338 * There are 2 flavors Abort and Commit. Basically the only differerence between | |
| 1339 * these 2 are what the database will show. (no change in to former, change in | |
| 1340 * the latter). | |
| 1341 */ | |
| 1342 static CK_RV | |
| 1343 sdb_complete(SDB *sdb, const char *cmd) | |
| 1344 { | |
| 1345 SDBPrivate *sdb_p = sdb->private; | |
| 1346 sqlite3 *sqlDB = NULL; | |
| 1347 sqlite3_stmt *stmt = NULL; | |
| 1348 int sqlerr = SQLITE_OK; | |
| 1349 CK_RV error = CKR_OK; | |
| 1350 int retry = 0; | |
| 1351 | |
| 1352 | |
| 1353 if ((sdb->sdb_flags & SDB_RDONLY) != 0) { | |
| 1354 return CKR_TOKEN_WRITE_PROTECTED; | |
| 1355 } | |
| 1356 | |
| 1357 /* We must have a transation database, or we shouldn't have arrived here */ | |
| 1358 PR_EnterMonitor(sdb_p->dbMon); | |
| 1359 PORT_Assert(sdb_p->sqlXactDB); | |
| 1360 if (sdb_p->sqlXactDB == NULL) { | |
| 1361 PR_ExitMonitor(sdb_p->dbMon); | |
| 1362 return CKR_GENERAL_ERROR; /* shouldn't happen */ | |
| 1363 } | |
| 1364 PORT_Assert( sdb_p->sqlXactThread == PR_GetCurrentThread()); | |
| 1365 if ( sdb_p->sqlXactThread != PR_GetCurrentThread()) { | |
| 1366 PR_ExitMonitor(sdb_p->dbMon); | |
| 1367 return CKR_GENERAL_ERROR; /* shouldn't happen */ | |
| 1368 } | |
| 1369 sqlDB = sdb_p->sqlXactDB; | |
| 1370 sdb_p->sqlXactDB = NULL; /* no one else can get to this DB, | |
| 1371 * safe to unlock */ | |
| 1372 sdb_p->sqlXactThread = NULL; | |
| 1373 PR_ExitMonitor(sdb_p->dbMon); | |
| 1374 | |
| 1375 sqlerr =sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL); | |
| 1376 | |
| 1377 do { | |
| 1378 sqlerr = sqlite3_step(stmt); | |
| 1379 if (sqlerr == SQLITE_BUSY) { | |
| 1380 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 1381 } | |
| 1382 } while (!sdb_done(sqlerr,&retry)); | |
| 1383 | |
| 1384 /* Pending BEGIN TRANSACTIONS Can move forward at this point. */ | |
| 1385 | |
| 1386 if (stmt) { | |
| 1387 sqlite3_reset(stmt); | |
| 1388 sqlite3_finalize(stmt); | |
| 1389 } | |
| 1390 | |
| 1391 /* we we have a cached DB image, update it as well */ | |
| 1392 if (sdb_p->cacheTable) { | |
| 1393 PR_EnterMonitor(sdb_p->dbMon); | |
| 1394 sdb_updateCache(sdb_p); | |
| 1395 PR_ExitMonitor(sdb_p->dbMon); | |
| 1396 } | |
| 1397 | |
| 1398 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1399 | |
| 1400 /* We just finished a transaction. | |
| 1401 * Free the database, and remove it from the list */ | |
| 1402 sqlite3_close(sqlDB); | |
| 1403 | |
| 1404 return error; | |
| 1405 } | |
| 1406 | |
| 1407 static const char COMMIT_CMD[] = "COMMIT TRANSACTION;"; | |
| 1408 CK_RV | |
| 1409 sdb_Commit(SDB *sdb) | |
| 1410 { | |
| 1411 CK_RV crv; | |
| 1412 LOCK_SQLITE() | |
| 1413 crv = sdb_complete(sdb,COMMIT_CMD); | |
| 1414 UNLOCK_SQLITE() | |
| 1415 return crv; | |
| 1416 } | |
| 1417 | |
| 1418 static const char ROLLBACK_CMD[] = "ROLLBACK TRANSACTION;"; | |
| 1419 CK_RV | |
| 1420 sdb_Abort(SDB *sdb) | |
| 1421 { | |
| 1422 CK_RV crv; | |
| 1423 LOCK_SQLITE() | |
| 1424 crv = sdb_complete(sdb,ROLLBACK_CMD); | |
| 1425 UNLOCK_SQLITE() | |
| 1426 return crv; | |
| 1427 } | |
| 1428 | |
| 1429 static int tableExists(sqlite3 *sqlDB, const char *tableName); | |
| 1430 | |
| 1431 static const char GET_PW_CMD[] = "SELECT ALL * FROM metaData WHERE id=$ID;"; | |
| 1432 CK_RV | |
| 1433 sdb_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2) | |
| 1434 { | |
| 1435 SDBPrivate *sdb_p = sdb->private; | |
| 1436 sqlite3 *sqlDB = sdb_p->sqlXactDB; | |
| 1437 sqlite3_stmt *stmt = NULL; | |
| 1438 int sqlerr = SQLITE_OK; | |
| 1439 CK_RV error = CKR_OK; | |
| 1440 int found = 0; | |
| 1441 int retry = 0; | |
| 1442 | |
| 1443 LOCK_SQLITE() | |
| 1444 error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); | |
| 1445 if (error != CKR_OK) { | |
| 1446 goto loser; | |
| 1447 } | |
| 1448 | |
| 1449 /* handle 'test' versions of the sqlite db */ | |
| 1450 sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL); | |
| 1451 /* Sigh, if we created a new table since we opened the database, | |
| 1452 * the database handle will not see the new table, we need to close this | |
| 1453 * database and reopen it. This is safe because we are holding the lock | |
| 1454 * still. */ | |
| 1455 if (sqlerr == SQLITE_SCHEMA) { | |
| 1456 sqlerr = sdb_reopenDBLocal(sdb_p, &sqlDB); | |
| 1457 if (sqlerr != SQLITE_OK) { | |
| 1458 goto loser; | |
| 1459 } | |
| 1460 sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL); | |
| 1461 } | |
| 1462 if (sqlerr != SQLITE_OK) goto loser; | |
| 1463 sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC); | |
| 1464 do { | |
| 1465 sqlerr = sqlite3_step(stmt); | |
| 1466 if (sqlerr == SQLITE_BUSY) { | |
| 1467 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 1468 } | |
| 1469 if (sqlerr == SQLITE_ROW) { | |
| 1470 const char *blobData; | |
| 1471 unsigned int len = item1->len; | |
| 1472 item1->len = sqlite3_column_bytes(stmt, 1); | |
| 1473 if (item1->len > len) { | |
| 1474 error = CKR_BUFFER_TOO_SMALL; | |
| 1475 continue; | |
| 1476 } | |
| 1477 blobData = sqlite3_column_blob(stmt, 1); | |
| 1478 PORT_Memcpy(item1->data,blobData, item1->len); | |
| 1479 if (item2) { | |
| 1480 len = item2->len; | |
| 1481 item2->len = sqlite3_column_bytes(stmt, 2); | |
| 1482 if (item2->len > len) { | |
| 1483 error = CKR_BUFFER_TOO_SMALL; | |
| 1484 continue; | |
| 1485 } | |
| 1486 blobData = sqlite3_column_blob(stmt, 2); | |
| 1487 PORT_Memcpy(item2->data,blobData, item2->len); | |
| 1488 } | |
| 1489 found = 1; | |
| 1490 } | |
| 1491 } while (!sdb_done(sqlerr,&retry)); | |
| 1492 | |
| 1493 loser: | |
| 1494 /* fix up the error if necessary */ | |
| 1495 if (error == CKR_OK) { | |
| 1496 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1497 if (!found && error == CKR_OK) { | |
| 1498 error = CKR_OBJECT_HANDLE_INVALID; | |
| 1499 } | |
| 1500 } | |
| 1501 | |
| 1502 if (stmt) { | |
| 1503 sqlite3_reset(stmt); | |
| 1504 sqlite3_finalize(stmt); | |
| 1505 } | |
| 1506 | |
| 1507 if (sqlDB) { | |
| 1508 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 1509 } | |
| 1510 UNLOCK_SQLITE() | |
| 1511 | |
| 1512 return error; | |
| 1513 } | |
| 1514 | |
| 1515 static const char PW_CREATE_TABLE_CMD[] = | |
| 1516 "CREATE TABLE metaData (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, item1, item2
);"; | |
| 1517 static const char PW_CREATE_CMD[] = | |
| 1518 "INSERT INTO metaData (id,item1,item2) VALUES($ID,$ITEM1,$ITEM2);"; | |
| 1519 static const char MD_CREATE_CMD[] = | |
| 1520 "INSERT INTO metaData (id,item1) VALUES($ID,$ITEM1);"; | |
| 1521 CK_RV | |
| 1522 sdb_PutMetaData(SDB *sdb, const char *id, const SECItem *item1, | |
| 1523 const SECItem *item2) | |
| 1524 { | |
| 1525 SDBPrivate *sdb_p = sdb->private; | |
| 1526 sqlite3 *sqlDB = sdb_p->sqlXactDB; | |
| 1527 sqlite3_stmt *stmt = NULL; | |
| 1528 int sqlerr = SQLITE_OK; | |
| 1529 CK_RV error = CKR_OK; | |
| 1530 int retry = 0; | |
| 1531 const char *cmd = PW_CREATE_CMD; | |
| 1532 | |
| 1533 if ((sdb->sdb_flags & SDB_RDONLY) != 0) { | |
| 1534 return CKR_TOKEN_WRITE_PROTECTED; | |
| 1535 } | |
| 1536 | |
| 1537 LOCK_SQLITE() | |
| 1538 error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); | |
| 1539 if (error != CKR_OK) { | |
| 1540 goto loser; | |
| 1541 } | |
| 1542 | |
| 1543 if (!tableExists(sqlDB, "metaData")) { | |
| 1544 sqlerr = sqlite3_exec(sqlDB, PW_CREATE_TABLE_CMD, NULL, 0, NULL); | |
| 1545 if (sqlerr != SQLITE_OK) goto loser; | |
| 1546 } | |
| 1547 if (item2 == NULL) { | |
| 1548 cmd = MD_CREATE_CMD; | |
| 1549 } | |
| 1550 sqlerr = sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL); | |
| 1551 if (sqlerr != SQLITE_OK) goto loser; | |
| 1552 sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC); | |
| 1553 if (sqlerr != SQLITE_OK) goto loser; | |
| 1554 sqlerr = sqlite3_bind_blob(stmt, 2, item1->data, item1->len, SQLITE_STATIC); | |
| 1555 if (sqlerr != SQLITE_OK) goto loser; | |
| 1556 if (item2) { | |
| 1557 sqlerr = sqlite3_bind_blob(stmt, 3, item2->data, | |
| 1558 item2->len, SQLITE_STATIC); | |
| 1559 if (sqlerr != SQLITE_OK) goto loser; | |
| 1560 } | |
| 1561 | |
| 1562 do { | |
| 1563 sqlerr = sqlite3_step(stmt); | |
| 1564 if (sqlerr == SQLITE_BUSY) { | |
| 1565 PR_Sleep(SDB_BUSY_RETRY_TIME); | |
| 1566 } | |
| 1567 } while (!sdb_done(sqlerr,&retry)); | |
| 1568 | |
| 1569 loser: | |
| 1570 /* fix up the error if necessary */ | |
| 1571 if (error == CKR_OK) { | |
| 1572 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1573 } | |
| 1574 | |
| 1575 if (stmt) { | |
| 1576 sqlite3_reset(stmt); | |
| 1577 sqlite3_finalize(stmt); | |
| 1578 } | |
| 1579 | |
| 1580 if (sqlDB) { | |
| 1581 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 1582 } | |
| 1583 UNLOCK_SQLITE() | |
| 1584 | |
| 1585 return error; | |
| 1586 } | |
| 1587 | |
| 1588 static const char RESET_CMD[] = "DROP TABLE IF EXISTS %s;"; | |
| 1589 CK_RV | |
| 1590 sdb_Reset(SDB *sdb) | |
| 1591 { | |
| 1592 SDBPrivate *sdb_p = sdb->private; | |
| 1593 sqlite3 *sqlDB = NULL; | |
| 1594 char *newStr; | |
| 1595 int sqlerr = SQLITE_OK; | |
| 1596 CK_RV error = CKR_OK; | |
| 1597 | |
| 1598 /* only Key databases can be reset */ | |
| 1599 if (sdb_p->type != SDB_KEY) { | |
| 1600 return CKR_OBJECT_HANDLE_INVALID; | |
| 1601 } | |
| 1602 | |
| 1603 LOCK_SQLITE() | |
| 1604 error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); | |
| 1605 if (error != CKR_OK) { | |
| 1606 goto loser; | |
| 1607 } | |
| 1608 | |
| 1609 /* delete the key table */ | |
| 1610 newStr = sqlite3_mprintf(RESET_CMD, sdb_p->table); | |
| 1611 if (newStr == NULL) { | |
| 1612 error = CKR_HOST_MEMORY; | |
| 1613 goto loser; | |
| 1614 } | |
| 1615 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 1616 sqlite3_free(newStr); | |
| 1617 | |
| 1618 if (sqlerr != SQLITE_OK) goto loser; | |
| 1619 | |
| 1620 /* delete the password entry table */ | |
| 1621 sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS metaData;", | |
| 1622 NULL, 0, NULL); | |
| 1623 | |
| 1624 loser: | |
| 1625 /* fix up the error if necessary */ | |
| 1626 if (error == CKR_OK) { | |
| 1627 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1628 } | |
| 1629 | |
| 1630 if (sqlDB) { | |
| 1631 sdb_closeDBLocal(sdb_p, sqlDB) ; | |
| 1632 } | |
| 1633 | |
| 1634 UNLOCK_SQLITE() | |
| 1635 return error; | |
| 1636 } | |
| 1637 | |
| 1638 | |
| 1639 CK_RV | |
| 1640 sdb_Close(SDB *sdb) | |
| 1641 { | |
| 1642 SDBPrivate *sdb_p = sdb->private; | |
| 1643 int sqlerr = SQLITE_OK; | |
| 1644 sdbDataType type = sdb_p->type; | |
| 1645 | |
| 1646 sqlerr = sqlite3_close(sdb_p->sqlReadDB); | |
| 1647 PORT_Free(sdb_p->sqlDBName); | |
| 1648 if (sdb_p->cacheTable) { | |
| 1649 sqlite3_free(sdb_p->cacheTable); | |
| 1650 } | |
| 1651 if (sdb_p->dbMon) { | |
| 1652 PR_DestroyMonitor(sdb_p->dbMon); | |
| 1653 } | |
| 1654 free(sdb_p); | |
| 1655 free(sdb); | |
| 1656 return sdb_mapSQLError(type, sqlerr); | |
| 1657 } | |
| 1658 | |
| 1659 | |
| 1660 /* | |
| 1661 * functions to support open | |
| 1662 */ | |
| 1663 | |
| 1664 static const char CHECK_TABLE_CMD[] = "SELECT ALL * FROM %s LIMIT 0;"; | |
| 1665 /* return 1 if sqlDB contains table 'tableName */ | |
| 1666 static int tableExists(sqlite3 *sqlDB, const char *tableName) | |
| 1667 { | |
| 1668 char * cmd = sqlite3_mprintf(CHECK_TABLE_CMD, tableName); | |
| 1669 int sqlerr = SQLITE_OK; | |
| 1670 | |
| 1671 if (cmd == NULL) { | |
| 1672 return 0; | |
| 1673 } | |
| 1674 | |
| 1675 sqlerr = sqlite3_exec(sqlDB, cmd, NULL, 0, 0); | |
| 1676 sqlite3_free(cmd); | |
| 1677 | |
| 1678 return (sqlerr == SQLITE_OK) ? 1 : 0; | |
| 1679 } | |
| 1680 | |
| 1681 void sdb_SetForkState(PRBool forked) | |
| 1682 { | |
| 1683 /* XXXright now this is a no-op. The global fork state in the softokn3 | |
| 1684 * shared library is already taken care of at the PKCS#11 level. | |
| 1685 * If and when we add fork state to the sqlite shared library and extern | |
| 1686 * interface, we will need to set it and reset it from here */ | |
| 1687 } | |
| 1688 | |
| 1689 /* | |
| 1690 * initialize a single database | |
| 1691 */ | |
| 1692 static const char INIT_CMD[] = | |
| 1693 "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)"; | |
| 1694 | |
| 1695 CK_RV | |
| 1696 sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, | |
| 1697 int *newInit, int flags, PRUint32 accessOps, SDB **pSdb) | |
| 1698 { | |
| 1699 int i; | |
| 1700 char *initStr = NULL; | |
| 1701 char *newStr; | |
| 1702 int inTransaction = 0; | |
| 1703 SDB *sdb = NULL; | |
| 1704 SDBPrivate *sdb_p = NULL; | |
| 1705 sqlite3 *sqlDB = NULL; | |
| 1706 int sqlerr = SQLITE_OK; | |
| 1707 CK_RV error = CKR_OK; | |
| 1708 char *cacheTable = NULL; | |
| 1709 PRIntervalTime now = 0; | |
| 1710 char *env; | |
| 1711 PRBool enableCache = PR_FALSE; | |
| 1712 PRBool create; | |
| 1713 | |
| 1714 *pSdb = NULL; | |
| 1715 *inUpdate = 0; | |
| 1716 | |
| 1717 /* sqlite3 doesn't have a flag to specify that we want to | |
| 1718 * open the database read only. If the db doesn't exist, | |
| 1719 * sqlite3 will always create it. | |
| 1720 */ | |
| 1721 LOCK_SQLITE(); | |
| 1722 create = (PR_Access(dbname, PR_ACCESS_EXISTS) != PR_SUCCESS); | |
| 1723 if ((flags == SDB_RDONLY) && create) { | |
| 1724 error = sdb_mapSQLError(type, SQLITE_CANTOPEN); | |
| 1725 goto loser; | |
| 1726 } | |
| 1727 sqlerr = sdb_openDB(dbname, &sqlDB, flags); | |
| 1728 if (sqlerr != SQLITE_OK) { | |
| 1729 error = sdb_mapSQLError(type, sqlerr); | |
| 1730 goto loser; | |
| 1731 } | |
| 1732 /* sql created the file, but it doesn't set appropriate modes for | |
| 1733 * a database */ | |
| 1734 if (create) { | |
| 1735 /* NO NSPR call for this? :( */ | |
| 1736 chmod (dbname, 0600); | |
| 1737 } | |
| 1738 | |
| 1739 if (flags != SDB_RDONLY) { | |
| 1740 sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL); | |
| 1741 if (sqlerr != SQLITE_OK) { | |
| 1742 error = sdb_mapSQLError(type, sqlerr); | |
| 1743 goto loser; | |
| 1744 } | |
| 1745 inTransaction = 1; | |
| 1746 } | |
| 1747 if (!tableExists(sqlDB,table)) { | |
| 1748 *newInit = 1; | |
| 1749 if (flags != SDB_CREATE) { | |
| 1750 error = sdb_mapSQLError(type, SQLITE_CANTOPEN); | |
| 1751 goto loser; | |
| 1752 } | |
| 1753 initStr = sqlite3_mprintf(""); | |
| 1754 for (i=0; initStr && i < known_attributes_size; i++) { | |
| 1755 newStr = sqlite3_mprintf("%s, a%x",initStr, known_attributes[i]); | |
| 1756 sqlite3_free(initStr); | |
| 1757 initStr = newStr; | |
| 1758 } | |
| 1759 if (initStr == NULL) { | |
| 1760 error = CKR_HOST_MEMORY; | |
| 1761 goto loser; | |
| 1762 } | |
| 1763 | |
| 1764 newStr = sqlite3_mprintf(INIT_CMD, table, initStr); | |
| 1765 sqlite3_free(initStr); | |
| 1766 if (newStr == NULL) { | |
| 1767 error = CKR_HOST_MEMORY; | |
| 1768 goto loser; | |
| 1769 } | |
| 1770 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 1771 sqlite3_free(newStr); | |
| 1772 if (sqlerr != SQLITE_OK) { | |
| 1773 error = sdb_mapSQLError(type, sqlerr); | |
| 1774 goto loser; | |
| 1775 } | |
| 1776 | |
| 1777 newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, table); | |
| 1778 if (newStr == NULL) { | |
| 1779 error = CKR_HOST_MEMORY; | |
| 1780 goto loser; | |
| 1781 } | |
| 1782 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 1783 sqlite3_free(newStr); | |
| 1784 if (sqlerr != SQLITE_OK) { | |
| 1785 error = sdb_mapSQLError(type, sqlerr); | |
| 1786 goto loser; | |
| 1787 } | |
| 1788 | |
| 1789 newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, table); | |
| 1790 if (newStr == NULL) { | |
| 1791 error = CKR_HOST_MEMORY; | |
| 1792 goto loser; | |
| 1793 } | |
| 1794 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 1795 sqlite3_free(newStr); | |
| 1796 if (sqlerr != SQLITE_OK) { | |
| 1797 error = sdb_mapSQLError(type, sqlerr); | |
| 1798 goto loser; | |
| 1799 } | |
| 1800 | |
| 1801 newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, table); | |
| 1802 if (newStr == NULL) { | |
| 1803 error = CKR_HOST_MEMORY; | |
| 1804 goto loser; | |
| 1805 } | |
| 1806 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 1807 sqlite3_free(newStr); | |
| 1808 if (sqlerr != SQLITE_OK) { | |
| 1809 error = sdb_mapSQLError(type, sqlerr); | |
| 1810 goto loser; | |
| 1811 } | |
| 1812 | |
| 1813 newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, table); | |
| 1814 if (newStr == NULL) { | |
| 1815 error = CKR_HOST_MEMORY; | |
| 1816 goto loser; | |
| 1817 } | |
| 1818 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
| 1819 sqlite3_free(newStr); | |
| 1820 if (sqlerr != SQLITE_OK) { | |
| 1821 error = sdb_mapSQLError(type, sqlerr); | |
| 1822 goto loser; | |
| 1823 } | |
| 1824 } | |
| 1825 /* | |
| 1826 * detect the case where we have created the database, but have | |
| 1827 * not yet updated it. | |
| 1828 * | |
| 1829 * We only check the Key database because only the key database has | |
| 1830 * a metaData table. The metaData table is created when a password | |
| 1831 * is set, or in the case of update, when a password is supplied. | |
| 1832 * If no key database exists, then the update would have happened immediatel
y | |
| 1833 * on noticing that the cert database didn't exist (see newInit set above). | |
| 1834 */ | |
| 1835 if (type == SDB_KEY && !tableExists(sqlDB, "metaData")) { | |
| 1836 *newInit = 1; | |
| 1837 } | |
| 1838 | |
| 1839 /* access to network filesystems are significantly slower than local ones | |
| 1840 * for database operations. In those cases we need to create a cached copy | |
| 1841 * of the database in a temporary location on the local disk. SQLITE | |
| 1842 * already provides a way to create a temporary table and initialize it, | |
| 1843 * so we use it for the cache (see sdb_buildCache for how it's done).*/ | |
| 1844 | |
| 1845 /* | |
| 1846 * we decide whether or not to use the cache based on the following input. | |
| 1847 * | |
| 1848 * NSS_SDB_USE_CACHE environment variable is non-existant or set to | |
| 1849 * anything other than "no" or "yes" ("auto", for instance). | |
| 1850 * This is the normal case. NSS will measure the performance of access | |
| 1851 * to the temp database versus the access to the users passed in | |
| 1852 * database location. If the temp database location is "significantly" | |
| 1853 * faster we will use the cache. | |
| 1854 * | |
| 1855 * NSS_SDB_USE_CACHE environment variable is set to "no": cache will not | |
| 1856 * be used. | |
| 1857 * | |
| 1858 * NSS_SDB_USE_CACHE environment variable is set to "yes": cache will | |
| 1859 * always be used. | |
| 1860 * | |
| 1861 * It is expected that most applications would use the "auto" selection, | |
| 1862 * the environment variable is primarily to simplify testing, and to | |
| 1863 * correct potential corner cases where */ | |
| 1864 | |
| 1865 env = PR_GetEnvSecure("NSS_SDB_USE_CACHE"); | |
| 1866 | |
| 1867 if (env && PORT_Strcasecmp(env,"no") == 0) { | |
| 1868 enableCache = PR_FALSE; | |
| 1869 } else if (env && PORT_Strcasecmp(env,"yes") == 0) { | |
| 1870 enableCache = PR_TRUE; | |
| 1871 } else { | |
| 1872 char *tempDir = NULL; | |
| 1873 PRUint32 tempOps = 0; | |
| 1874 /* | |
| 1875 * Use PR_Access to determine how expensive it | |
| 1876 * is to check for the existance of a local file compared to the same | |
| 1877 * check in the temp directory. If the temp directory is faster, cache | |
| 1878 * the database there. */ | |
| 1879 tempDir = sdb_getTempDir(sqlDB); | |
| 1880 if (tempDir) { | |
| 1881 tempOps = sdb_measureAccess(tempDir); | |
| 1882 PORT_Free(tempDir); | |
| 1883 | |
| 1884 /* There is a cost to continually copying the database. | |
| 1885 * Account for that cost with the arbitrary factor of 10 */ | |
| 1886 enableCache = (PRBool)(tempOps > accessOps * 10); | |
| 1887 } | |
| 1888 } | |
| 1889 | |
| 1890 if (enableCache) { | |
| 1891 /* try to set the temp store to memory.*/ | |
| 1892 sqlite3_exec(sqlDB, "PRAGMA temp_store=MEMORY", NULL, 0, NULL); | |
| 1893 /* Failure to set the temp store to memory is not fatal, | |
| 1894 * ignore the error */ | |
| 1895 | |
| 1896 cacheTable = sqlite3_mprintf("%sCache",table); | |
| 1897 if (cacheTable == NULL) { | |
| 1898 error = CKR_HOST_MEMORY; | |
| 1899 goto loser; | |
| 1900 } | |
| 1901 /* build the cache table */ | |
| 1902 error = sdb_buildCache(sqlDB, type, cacheTable, table); | |
| 1903 if (error != CKR_OK) { | |
| 1904 goto loser; | |
| 1905 } | |
| 1906 /* initialize the last cache build time */ | |
| 1907 now = PR_IntervalNow(); | |
| 1908 } | |
| 1909 | |
| 1910 sdb = (SDB *) malloc(sizeof(SDB)); | |
| 1911 sdb_p = (SDBPrivate *) malloc(sizeof(SDBPrivate)); | |
| 1912 | |
| 1913 /* invariant fields */ | |
| 1914 sdb_p->sqlDBName = PORT_Strdup(dbname); | |
| 1915 sdb_p->type = type; | |
| 1916 sdb_p->table = table; | |
| 1917 sdb_p->cacheTable = cacheTable; | |
| 1918 sdb_p->lastUpdateTime = now; | |
| 1919 /* set the cache delay time. This is how long we will wait before we | |
| 1920 * decide the existing cache is stale. Currently set to 10 sec */ | |
| 1921 sdb_p->updateInterval = PR_SecondsToInterval(10); | |
| 1922 sdb_p->dbMon = PR_NewMonitor(); | |
| 1923 /* these fields are protected by the lock */ | |
| 1924 sdb_p->sqlXactDB = NULL; | |
| 1925 sdb_p->sqlXactThread = NULL; | |
| 1926 sdb->private = sdb_p; | |
| 1927 sdb->version = 0; | |
| 1928 sdb->sdb_flags = flags | SDB_HAS_META; | |
| 1929 sdb->app_private = NULL; | |
| 1930 sdb->sdb_FindObjectsInit = sdb_FindObjectsInit; | |
| 1931 sdb->sdb_FindObjects = sdb_FindObjects; | |
| 1932 sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal; | |
| 1933 sdb->sdb_GetAttributeValue = sdb_GetAttributeValue; | |
| 1934 sdb->sdb_SetAttributeValue = sdb_SetAttributeValue; | |
| 1935 sdb->sdb_CreateObject = sdb_CreateObject; | |
| 1936 sdb->sdb_DestroyObject = sdb_DestroyObject; | |
| 1937 sdb->sdb_GetMetaData = sdb_GetMetaData; | |
| 1938 sdb->sdb_PutMetaData = sdb_PutMetaData; | |
| 1939 sdb->sdb_Begin = sdb_Begin; | |
| 1940 sdb->sdb_Commit = sdb_Commit; | |
| 1941 sdb->sdb_Abort = sdb_Abort; | |
| 1942 sdb->sdb_Reset = sdb_Reset; | |
| 1943 sdb->sdb_Close = sdb_Close; | |
| 1944 sdb->sdb_SetForkState = sdb_SetForkState; | |
| 1945 | |
| 1946 if (inTransaction) { | |
| 1947 sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL); | |
| 1948 if (sqlerr != SQLITE_OK) { | |
| 1949 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
| 1950 goto loser; | |
| 1951 } | |
| 1952 inTransaction = 0; | |
| 1953 } | |
| 1954 | |
| 1955 sdb_p->sqlReadDB = sqlDB; | |
| 1956 | |
| 1957 *pSdb = sdb; | |
| 1958 UNLOCK_SQLITE(); | |
| 1959 return CKR_OK; | |
| 1960 | |
| 1961 loser: | |
| 1962 /* lots of stuff to do */ | |
| 1963 if (inTransaction) { | |
| 1964 sqlite3_exec(sqlDB, ROLLBACK_CMD, NULL, 0, NULL); | |
| 1965 } | |
| 1966 if (sdb) { | |
| 1967 free(sdb); | |
| 1968 } | |
| 1969 if (sdb_p) { | |
| 1970 free(sdb_p); | |
| 1971 } | |
| 1972 if (sqlDB) { | |
| 1973 sqlite3_close(sqlDB); | |
| 1974 } | |
| 1975 UNLOCK_SQLITE(); | |
| 1976 return error; | |
| 1977 | |
| 1978 } | |
| 1979 | |
| 1980 | |
| 1981 /* sdbopen */ | |
| 1982 CK_RV | |
| 1983 s_open(const char *directory, const char *certPrefix, const char *keyPrefix, | |
| 1984 int cert_version, int key_version, int flags, | |
| 1985 SDB **certdb, SDB **keydb, int *newInit) | |
| 1986 { | |
| 1987 char *cert = sdb_BuildFileName(directory, certPrefix, | |
| 1988 "cert", cert_version); | |
| 1989 char *key = sdb_BuildFileName(directory, keyPrefix, | |
| 1990 "key", key_version); | |
| 1991 CK_RV error = CKR_OK; | |
| 1992 int inUpdate; | |
| 1993 PRUint32 accessOps; | |
| 1994 | |
| 1995 if (certdb) | |
| 1996 *certdb = NULL; | |
| 1997 if (keydb) | |
| 1998 *keydb = NULL; | |
| 1999 *newInit = 0; | |
| 2000 | |
| 2001 #ifdef SQLITE_UNSAFE_THREADS | |
| 2002 if (sqlite_lock == NULL) { | |
| 2003 sqlite_lock = PR_NewLock(); | |
| 2004 if (sqlite_lock == NULL) { | |
| 2005 error = CKR_HOST_MEMORY; | |
| 2006 goto loser; | |
| 2007 } | |
| 2008 } | |
| 2009 #endif | |
| 2010 | |
| 2011 /* how long does it take to test for a non-existant file in our working | |
| 2012 * directory? Allows us to test if we may be on a network file system */ | |
| 2013 accessOps = 1; | |
| 2014 { | |
| 2015 char *env; | |
| 2016 env = PR_GetEnvSecure("NSS_SDB_USE_CACHE"); | |
| 2017 /* If the environment variable is set to yes or no, sdb_init() will | |
| 2018 * ignore the value of accessOps, and we can skip the measuring.*/ | |
| 2019 if (!env || ((PORT_Strcasecmp(env, "no") != 0) && | |
| 2020 (PORT_Strcasecmp(env, "yes") != 0))){ | |
| 2021 accessOps = sdb_measureAccess(directory); | |
| 2022 } | |
| 2023 } | |
| 2024 | |
| 2025 /* | |
| 2026 * open the cert data base | |
| 2027 */ | |
| 2028 if (certdb) { | |
| 2029 /* initialize Certificate database */ | |
| 2030 error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate, | |
| 2031 newInit, flags, accessOps, certdb); | |
| 2032 if (error != CKR_OK) { | |
| 2033 goto loser; | |
| 2034 } | |
| 2035 } | |
| 2036 | |
| 2037 /* | |
| 2038 * open the key data base: | |
| 2039 * NOTE:if we want to implement a single database, we open | |
| 2040 * the same database file as the certificate here. | |
| 2041 * | |
| 2042 * cert an key db's have different tables, so they will not | |
| 2043 * conflict. | |
| 2044 */ | |
| 2045 if (keydb) { | |
| 2046 /* initialize the Key database */ | |
| 2047 error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate, | |
| 2048 newInit, flags, accessOps, keydb); | |
| 2049 if (error != CKR_OK) { | |
| 2050 goto loser; | |
| 2051 } | |
| 2052 } | |
| 2053 | |
| 2054 | |
| 2055 loser: | |
| 2056 if (cert) { | |
| 2057 sqlite3_free(cert); | |
| 2058 } | |
| 2059 if (key) { | |
| 2060 sqlite3_free(key); | |
| 2061 } | |
| 2062 | |
| 2063 if (error != CKR_OK) { | |
| 2064 /* currently redundant, but could be necessary if more code is added | |
| 2065 * just before loser */ | |
| 2066 if (keydb && *keydb) { | |
| 2067 sdb_Close(*keydb); | |
| 2068 } | |
| 2069 if (certdb && *certdb) { | |
| 2070 sdb_Close(*certdb); | |
| 2071 } | |
| 2072 } | |
| 2073 | |
| 2074 return error; | |
| 2075 } | |
| 2076 | |
| 2077 CK_RV | |
| 2078 s_shutdown() | |
| 2079 { | |
| 2080 #ifdef SQLITE_UNSAFE_THREADS | |
| 2081 if (sqlite_lock) { | |
| 2082 PR_DestroyLock(sqlite_lock); | |
| 2083 sqlite_lock = NULL; | |
| 2084 } | |
| 2085 #endif | |
| 2086 return CKR_OK; | |
| 2087 } | |
| OLD | NEW |