1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/softoken/sdb.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2089 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +/* 1.8 + * This file implements PKCS 11 on top of our existing security modules 1.9 + * 1.10 + * For more information about PKCS 11 See PKCS 11 Token Inteface Standard. 1.11 + * This implementation has two slots: 1.12 + * slot 1 is our generic crypto support. It does not require login. 1.13 + * It supports Public Key ops, and all they bulk ciphers and hashes. 1.14 + * It can also support Private Key ops for imported Private keys. It does 1.15 + * not have any token storage. 1.16 + * slot 2 is our private key support. It requires a login before use. It 1.17 + * can store Private Keys and Certs as token objects. Currently only private 1.18 + * keys and their associated Certificates are saved on the token. 1.19 + * 1.20 + * In this implementation, session objects are only visible to the session 1.21 + * that created or generated them. 1.22 + */ 1.23 + 1.24 +#include "sdb.h" 1.25 +#include "pkcs11t.h" 1.26 +#include "seccomon.h" 1.27 +#include <sqlite3.h> 1.28 +#include "prthread.h" 1.29 +#include "prio.h" 1.30 +#include <stdio.h> 1.31 +#include "secport.h" 1.32 +#include "prmon.h" 1.33 +#include "prenv.h" 1.34 +#include "prprf.h" 1.35 +#include "prsystem.h" /* for PR_GetDirectorySeparator() */ 1.36 +#include <sys/stat.h> 1.37 +#if defined(_WIN32) 1.38 +#include <io.h> 1.39 +#include <windows.h> 1.40 +#elif defined(XP_UNIX) 1.41 +#include <unistd.h> 1.42 +#endif 1.43 + 1.44 +#ifdef SQLITE_UNSAFE_THREADS 1.45 +#include "prlock.h" 1.46 +/* 1.47 + * SQLite can be compiled to be thread safe or not. 1.48 + * turn on SQLITE_UNSAFE_THREADS if the OS does not support 1.49 + * a thread safe version of sqlite. 1.50 + */ 1.51 +static PRLock *sqlite_lock = NULL; 1.52 + 1.53 +#define LOCK_SQLITE() PR_Lock(sqlite_lock); 1.54 +#define UNLOCK_SQLITE() PR_Unlock(sqlite_lock); 1.55 +#else 1.56 +#define LOCK_SQLITE() 1.57 +#define UNLOCK_SQLITE() 1.58 +#endif 1.59 + 1.60 +typedef enum { 1.61 + SDB_CERT = 1, 1.62 + SDB_KEY = 2 1.63 +} sdbDataType; 1.64 + 1.65 +/* 1.66 + * defines controlling how long we wait to acquire locks. 1.67 + * 1.68 + * SDB_SQLITE_BUSY_TIMEOUT specifies how long (in milliseconds) 1.69 + * sqlite will wait on lock. If that timeout expires, sqlite will 1.70 + * return SQLITE_BUSY. 1.71 + * SDB_BUSY_RETRY_TIME specifies how many seconds the sdb_ code waits 1.72 + * after receiving a busy before retrying. 1.73 + * SDB_MAX_BUSY_RETRIES specifies how many times the sdb_ will retry on 1.74 + * a busy condition. 1.75 + * 1.76 + * SDB_SQLITE_BUSY_TIMEOUT affects all opertions, both manual 1.77 + * (prepare/step/reset/finalize) and automatic (sqlite3_exec()). 1.78 + * SDB_BUSY_RETRY_TIME and SDB_MAX_BUSY_RETRIES only affect manual operations 1.79 + * 1.80 + * total wait time for automatic operations: 1.81 + * 1 second (SDB_SQLITE_BUSY_TIMEOUT/1000). 1.82 + * total wait time for manual operations: 1.83 + * (1 second + 5 seconds) * 10 = 60 seconds. 1.84 + * (SDB_SQLITE_BUSY_TIMEOUT/1000 + SDB_BUSY_RETRY_TIME)*SDB_MAX_BUSY_RETRIES 1.85 + */ 1.86 +#define SDB_SQLITE_BUSY_TIMEOUT 1000 /* milliseconds */ 1.87 +#define SDB_BUSY_RETRY_TIME 5 /* seconds */ 1.88 +#define SDB_MAX_BUSY_RETRIES 10 1.89 + 1.90 +/* 1.91 + * Note on use of sqlReadDB: Only one thread at a time may have an actual 1.92 + * operation going on given sqlite3 * database. An operation is defined as 1.93 + * the time from a sqlite3_prepare() until the sqlite3_finalize(). 1.94 + * Multiple sqlite3 * databases can be open and have simultaneous operations 1.95 + * going. We use the sqlXactDB for all write operations. This database 1.96 + * is only opened when we first create a transaction and closed when the 1.97 + * transaction is complete. sqlReadDB is open when we first opened the database 1.98 + * and is used for all read operation. It's use is protected by a monitor. This 1.99 + * is because an operation can span the use of FindObjectsInit() through the 1.100 + * call to FindObjectsFinal(). In the intermediate time it is possible to call 1.101 + * other operations like NSC_GetAttributeValue */ 1.102 + 1.103 +struct SDBPrivateStr { 1.104 + char *sqlDBName; /* invariant, path to this database */ 1.105 + sqlite3 *sqlXactDB; /* access protected by dbMon, use protected 1.106 + * by the transaction. Current transaction db*/ 1.107 + PRThread *sqlXactThread; /* protected by dbMon, 1.108 + * current transaction thread */ 1.109 + sqlite3 *sqlReadDB; /* use protected by dbMon, value invariant */ 1.110 + PRIntervalTime lastUpdateTime; /* last time the cache was updated */ 1.111 + PRIntervalTime updateInterval; /* how long the cache can go before it 1.112 + * must be updated again */ 1.113 + sdbDataType type; /* invariant, database type */ 1.114 + char *table; /* invariant, SQL table which contains the db */ 1.115 + char *cacheTable; /* invariant, SQL table cache of db */ 1.116 + PRMonitor *dbMon; /* invariant, monitor to protect 1.117 + * sqlXact* fields, and use of the sqlReadDB */ 1.118 +}; 1.119 + 1.120 +typedef struct SDBPrivateStr SDBPrivate; 1.121 + 1.122 +/* 1.123 + * known attributes 1.124 + */ 1.125 +static const CK_ATTRIBUTE_TYPE known_attributes[] = { 1.126 + CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, 1.127 + CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, 1.128 + CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, 1.129 + CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, 1.130 + CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, 1.131 + CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, 1.132 + CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, 1.133 + CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, 1.134 + CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, 1.135 + CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, 1.136 + CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, 1.137 + CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, 1.138 + CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, 1.139 + CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, 1.140 + CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, 1.141 + CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, 1.142 + CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, 1.143 + CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, 1.144 + CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, 1.145 + CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, 1.146 + CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, 1.147 + CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NETSCAPE_URL, CKA_NETSCAPE_EMAIL, 1.148 + CKA_NETSCAPE_SMIME_INFO, CKA_NETSCAPE_SMIME_TIMESTAMP, 1.149 + CKA_NETSCAPE_PKCS8_SALT, CKA_NETSCAPE_PASSWORD_CHECK, CKA_NETSCAPE_EXPIRES, 1.150 + CKA_NETSCAPE_KRL, CKA_NETSCAPE_PQG_COUNTER, CKA_NETSCAPE_PQG_SEED, 1.151 + CKA_NETSCAPE_PQG_H, CKA_NETSCAPE_PQG_SEED_BITS, CKA_NETSCAPE_MODULE_SPEC, 1.152 + CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, 1.153 + CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, 1.154 + CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, 1.155 + CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, 1.156 + CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, 1.157 + CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, 1.158 + CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, 1.159 + CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS 1.160 +}; 1.161 + 1.162 +static int known_attributes_size= sizeof(known_attributes)/ 1.163 + sizeof(known_attributes[0]); 1.164 + 1.165 +/* Magic for an explicit NULL. NOTE: ideally this should be 1.166 + * out of band data. Since it's not completely out of band, pick 1.167 + * a value that has no meaning to any existing PKCS #11 attributes. 1.168 + * This value is 1) not a valid string (imbedded '\0'). 2) not a U_LONG 1.169 + * or a normal key (too short). 3) not a bool (too long). 4) not an RSA 1.170 + * public exponent (too many bits). 1.171 + */ 1.172 +const unsigned char SQLITE_EXPLICIT_NULL[] = { 0xa5, 0x0, 0x5a }; 1.173 +#define SQLITE_EXPLICIT_NULL_LEN 3 1.174 + 1.175 +/* 1.176 + * determine when we've completed our tasks 1.177 + */ 1.178 +static int 1.179 +sdb_done(int err, int *count) 1.180 +{ 1.181 + /* allow as many rows as the database wants to give */ 1.182 + if (err == SQLITE_ROW) { 1.183 + *count = 0; 1.184 + return 0; 1.185 + } 1.186 + if (err != SQLITE_BUSY) { 1.187 + return 1; 1.188 + } 1.189 + /* err == SQLITE_BUSY, Dont' retry forever in this case */ 1.190 + if (++(*count) >= SDB_MAX_BUSY_RETRIES) { 1.191 + return 1; 1.192 + } 1.193 + return 0; 1.194 +} 1.195 + 1.196 +/* 1.197 + * find out where sqlite stores the temp tables. We do this by replicating 1.198 + * the logic from sqlite. 1.199 + */ 1.200 +#if defined(_WIN32) 1.201 +static char * 1.202 +sdb_getFallbackTempDir(void) 1.203 +{ 1.204 + /* sqlite uses sqlite3_temp_directory if it is not NULL. We don't have 1.205 + * access to sqlite3_temp_directory because it is not exported from 1.206 + * sqlite3.dll. Assume sqlite3_win32_set_directory isn't called and 1.207 + * sqlite3_temp_directory is NULL. 1.208 + */ 1.209 + char path[MAX_PATH]; 1.210 + DWORD rv; 1.211 + size_t len; 1.212 + 1.213 + rv = GetTempPathA(MAX_PATH, path); 1.214 + if (rv > MAX_PATH || rv == 0) 1.215 + return NULL; 1.216 + len = strlen(path); 1.217 + if (len == 0) 1.218 + return NULL; 1.219 + /* The returned string ends with a backslash, for example, "C:\TEMP\". */ 1.220 + if (path[len - 1] == '\\') 1.221 + path[len - 1] = '\0'; 1.222 + return PORT_Strdup(path); 1.223 +} 1.224 +#elif defined(XP_UNIX) 1.225 +static char * 1.226 +sdb_getFallbackTempDir(void) 1.227 +{ 1.228 + const char *azDirs[] = { 1.229 + NULL, 1.230 + NULL, 1.231 + "/var/tmp", 1.232 + "/usr/tmp", 1.233 + "/tmp", 1.234 + NULL /* List terminator */ 1.235 + }; 1.236 + unsigned int i; 1.237 + struct stat buf; 1.238 + const char *zDir = NULL; 1.239 + 1.240 + azDirs[0] = sqlite3_temp_directory; 1.241 + azDirs[1] = getenv("TMPDIR"); 1.242 + 1.243 + for (i = 0; i < PR_ARRAY_SIZE(azDirs); i++) { 1.244 + zDir = azDirs[i]; 1.245 + if (zDir == NULL) continue; 1.246 + if (stat(zDir, &buf)) continue; 1.247 + if (!S_ISDIR(buf.st_mode)) continue; 1.248 + if (access(zDir, 07)) continue; 1.249 + break; 1.250 + } 1.251 + 1.252 + if (zDir == NULL) 1.253 + return NULL; 1.254 + return PORT_Strdup(zDir); 1.255 +} 1.256 +#else 1.257 +#error "sdb_getFallbackTempDir not implemented" 1.258 +#endif 1.259 + 1.260 +#ifndef SQLITE_FCNTL_TEMPFILENAME 1.261 +/* SQLITE_FCNTL_TEMPFILENAME was added in SQLite 3.7.15 */ 1.262 +#define SQLITE_FCNTL_TEMPFILENAME 16 1.263 +#endif 1.264 + 1.265 +static char * 1.266 +sdb_getTempDir(sqlite3 *sqlDB) 1.267 +{ 1.268 + int sqlrv; 1.269 + char *result = NULL; 1.270 + char *tempName = NULL; 1.271 + char *foundSeparator = NULL; 1.272 + 1.273 + /* Obtain temporary filename in sqlite's directory for temporary tables */ 1.274 + sqlrv = sqlite3_file_control(sqlDB, 0, SQLITE_FCNTL_TEMPFILENAME, 1.275 + (void*)&tempName); 1.276 + if (sqlrv == SQLITE_NOTFOUND) { 1.277 + /* SQLITE_FCNTL_TEMPFILENAME not implemented because we are using 1.278 + * an older SQLite. */ 1.279 + return sdb_getFallbackTempDir(); 1.280 + } 1.281 + if (sqlrv != SQLITE_OK) { 1.282 + return NULL; 1.283 + } 1.284 + 1.285 + /* We'll extract the temporary directory from tempName */ 1.286 + foundSeparator = PORT_Strrchr(tempName, PR_GetDirectorySeparator()); 1.287 + if (foundSeparator) { 1.288 + /* We shorten the temp filename string to contain only 1.289 + * the directory name (including the trailing separator). 1.290 + * We know the byte after the foundSeparator position is 1.291 + * safe to use, in the shortest scenario it contains the 1.292 + * end-of-string byte. 1.293 + * By keeping the separator at the found position, it will 1.294 + * even work if tempDir consists of the separator, only. 1.295 + * (In this case the toplevel directory will be used for 1.296 + * access speed testing). */ 1.297 + ++foundSeparator; 1.298 + *foundSeparator = 0; 1.299 + 1.300 + /* Now we copy the directory name for our caller */ 1.301 + result = PORT_Strdup(tempName); 1.302 + } 1.303 + 1.304 + sqlite3_free(tempName); 1.305 + return result; 1.306 +} 1.307 + 1.308 +/* 1.309 + * Map SQL_LITE errors to PKCS #11 errors as best we can. 1.310 + */ 1.311 +static CK_RV 1.312 +sdb_mapSQLError(sdbDataType type, int sqlerr) 1.313 +{ 1.314 + switch (sqlerr) { 1.315 + /* good matches */ 1.316 + case SQLITE_OK: 1.317 + case SQLITE_DONE: 1.318 + return CKR_OK; 1.319 + case SQLITE_NOMEM: 1.320 + return CKR_HOST_MEMORY; 1.321 + case SQLITE_READONLY: 1.322 + return CKR_TOKEN_WRITE_PROTECTED; 1.323 + /* close matches */ 1.324 + case SQLITE_AUTH: 1.325 + case SQLITE_PERM: 1.326 + /*return CKR_USER_NOT_LOGGED_IN; */ 1.327 + case SQLITE_CANTOPEN: 1.328 + case SQLITE_NOTFOUND: 1.329 + /* NSS distiguishes between failure to open the cert and the key db */ 1.330 + return type == SDB_CERT ? 1.331 + CKR_NETSCAPE_CERTDB_FAILED : CKR_NETSCAPE_KEYDB_FAILED; 1.332 + case SQLITE_IOERR: 1.333 + return CKR_DEVICE_ERROR; 1.334 + default: 1.335 + break; 1.336 + } 1.337 + return CKR_GENERAL_ERROR; 1.338 +} 1.339 + 1.340 + 1.341 +/* 1.342 + * build up database name from a directory, prefix, name, version and flags. 1.343 + */ 1.344 +static char *sdb_BuildFileName(const char * directory, 1.345 + const char *prefix, const char *type, 1.346 + int version) 1.347 +{ 1.348 + char *dbname = NULL; 1.349 + /* build the full dbname */ 1.350 + dbname = sqlite3_mprintf("%s%c%s%s%d.db", directory, 1.351 + (int)(unsigned char)PR_GetDirectorySeparator(), 1.352 + prefix, type, version); 1.353 + return dbname; 1.354 +} 1.355 + 1.356 + 1.357 +/* 1.358 + * find out how expensive the access system call is for non-existant files 1.359 + * in the given directory. Return the number of operations done in 33 ms. 1.360 + */ 1.361 +static PRUint32 1.362 +sdb_measureAccess(const char *directory) 1.363 +{ 1.364 + PRUint32 i; 1.365 + PRIntervalTime time; 1.366 + PRIntervalTime delta; 1.367 + PRIntervalTime duration = PR_MillisecondsToInterval(33); 1.368 + const char *doesntExistName = "_dOeSnotExist_.db"; 1.369 + char *temp, *tempStartOfFilename; 1.370 + size_t maxTempLen, maxFileNameLen, directoryLength; 1.371 + 1.372 + /* no directory, just return one */ 1.373 + if (directory == NULL) { 1.374 + return 1; 1.375 + } 1.376 + 1.377 + /* our calculation assumes time is a 4 bytes == 32 bit integer */ 1.378 + PORT_Assert(sizeof(time) == 4); 1.379 + 1.380 + directoryLength = strlen(directory); 1.381 + 1.382 + maxTempLen = directoryLength + strlen(doesntExistName) 1.383 + + 1 /* potential additional separator char */ 1.384 + + 11 /* max chars for 32 bit int plus potential sign */ 1.385 + + 1; /* zero terminator */ 1.386 + 1.387 + temp = PORT_Alloc(maxTempLen); 1.388 + if (!temp) { 1.389 + return 1; 1.390 + } 1.391 + 1.392 + /* We'll copy directory into temp just once, then ensure it ends 1.393 + * with the directory separator, then remember the position after 1.394 + * the separator, and calculate the number of remaining bytes. */ 1.395 + 1.396 + strcpy(temp, directory); 1.397 + if (directory[directoryLength - 1] != PR_GetDirectorySeparator()) { 1.398 + temp[directoryLength++] = PR_GetDirectorySeparator(); 1.399 + } 1.400 + tempStartOfFilename = temp + directoryLength; 1.401 + maxFileNameLen = maxTempLen - directoryLength; 1.402 + 1.403 + /* measure number of Access operations that can be done in 33 milliseconds 1.404 + * (1/30'th of a second), or 10000 operations, which ever comes first. 1.405 + */ 1.406 + time = PR_IntervalNow(); 1.407 + for (i=0; i < 10000u; i++) { 1.408 + PRIntervalTime next; 1.409 + 1.410 + /* We'll use the variable part first in the filename string, just in 1.411 + * case it's longer than assumed, so if anything gets cut off, it 1.412 + * will be cut off from the constant part. 1.413 + * This code assumes the directory name at the beginning of 1.414 + * temp remains unchanged during our loop. */ 1.415 + PR_snprintf(tempStartOfFilename, maxFileNameLen, 1.416 + ".%lu%s", (PRUint32)(time+i), doesntExistName); 1.417 + PR_Access(temp,PR_ACCESS_EXISTS); 1.418 + next = PR_IntervalNow(); 1.419 + delta = next - time; 1.420 + if (delta >= duration) 1.421 + break; 1.422 + } 1.423 + 1.424 + PORT_Free(temp); 1.425 + 1.426 + /* always return 1 or greater */ 1.427 + return i ? i : 1u; 1.428 +} 1.429 + 1.430 +/* 1.431 + * some file sytems are very slow to run sqlite3 on, particularly if the 1.432 + * access count is pretty high. On these filesystems is faster to create 1.433 + * a temporary database on the local filesystem and access that. This 1.434 + * code uses a temporary table to create that cache. Temp tables are 1.435 + * automatically cleared when the database handle it was created on 1.436 + * Is freed. 1.437 + */ 1.438 +static const char DROP_CACHE_CMD[] = "DROP TABLE %s"; 1.439 +static const char CREATE_CACHE_CMD[] = 1.440 + "CREATE TEMPORARY TABLE %s AS SELECT * FROM %s"; 1.441 +static const char CREATE_ISSUER_INDEX_CMD[] = 1.442 + "CREATE INDEX issuer ON %s (a81)"; 1.443 +static const char CREATE_SUBJECT_INDEX_CMD[] = 1.444 + "CREATE INDEX subject ON %s (a101)"; 1.445 +static const char CREATE_LABEL_INDEX_CMD[] = "CREATE INDEX label ON %s (a3)"; 1.446 +static const char CREATE_ID_INDEX_CMD[] = "CREATE INDEX ckaid ON %s (a102)"; 1.447 + 1.448 +static CK_RV 1.449 +sdb_buildCache(sqlite3 *sqlDB, sdbDataType type, 1.450 + const char *cacheTable, const char *table) 1.451 +{ 1.452 + char *newStr; 1.453 + int sqlerr = SQLITE_OK; 1.454 + 1.455 + newStr = sqlite3_mprintf(CREATE_CACHE_CMD, cacheTable, table); 1.456 + if (newStr == NULL) { 1.457 + return CKR_HOST_MEMORY; 1.458 + } 1.459 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.460 + sqlite3_free(newStr); 1.461 + if (sqlerr != SQLITE_OK) { 1.462 + return sdb_mapSQLError(type, sqlerr); 1.463 + } 1.464 + /* failure to create the indexes is not an issue */ 1.465 + newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, cacheTable); 1.466 + if (newStr == NULL) { 1.467 + return CKR_OK; 1.468 + } 1.469 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.470 + sqlite3_free(newStr); 1.471 + newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, cacheTable); 1.472 + if (newStr == NULL) { 1.473 + return CKR_OK; 1.474 + } 1.475 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.476 + sqlite3_free(newStr); 1.477 + newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, cacheTable); 1.478 + if (newStr == NULL) { 1.479 + return CKR_OK; 1.480 + } 1.481 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.482 + sqlite3_free(newStr); 1.483 + newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, cacheTable); 1.484 + if (newStr == NULL) { 1.485 + return CKR_OK; 1.486 + } 1.487 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.488 + sqlite3_free(newStr); 1.489 + return CKR_OK; 1.490 +} 1.491 + 1.492 +/* 1.493 + * update the cache and the data records describing it. 1.494 + * The cache is updated by dropping the temp database and recreating it. 1.495 + */ 1.496 +static CK_RV 1.497 +sdb_updateCache(SDBPrivate *sdb_p) 1.498 +{ 1.499 + int sqlerr = SQLITE_OK; 1.500 + CK_RV error = CKR_OK; 1.501 + char *newStr; 1.502 + 1.503 + /* drop the old table */ 1.504 + newStr = sqlite3_mprintf(DROP_CACHE_CMD, sdb_p->cacheTable); 1.505 + if (newStr == NULL) { 1.506 + return CKR_HOST_MEMORY; 1.507 + } 1.508 + sqlerr = sqlite3_exec(sdb_p->sqlReadDB, newStr, NULL, 0, NULL); 1.509 + sqlite3_free(newStr); 1.510 + if ((sqlerr != SQLITE_OK) && (sqlerr != SQLITE_ERROR )) { 1.511 + /* something went wrong with the drop, don't try to refresh... 1.512 + * NOTE: SQLITE_ERROR is returned if the table doesn't exist. In 1.513 + * that case, we just continue on and try to reload it */ 1.514 + return sdb_mapSQLError(sdb_p->type, sqlerr); 1.515 + } 1.516 + 1.517 + 1.518 + /* set up the new table */ 1.519 + error = sdb_buildCache(sdb_p->sqlReadDB,sdb_p->type, 1.520 + sdb_p->cacheTable,sdb_p->table ); 1.521 + if (error == CKR_OK) { 1.522 + /* we have a new cache! */ 1.523 + sdb_p->lastUpdateTime = PR_IntervalNow(); 1.524 + } 1.525 + return error; 1.526 +} 1.527 + 1.528 +/* 1.529 + * The sharing of sqlite3 handles across threads is tricky. Older versions 1.530 + * couldn't at all, but newer ones can under strict conditions. Basically 1.531 + * no 2 threads can use the same handle while another thread has an open 1.532 + * stmt running. Once the sqlite3_stmt is finalized, another thread can then 1.533 + * use the database handle. 1.534 + * 1.535 + * We use monitors to protect against trying to use a database before 1.536 + * it's sqlite3_stmt is finalized. This is preferable to the opening and 1.537 + * closing the database each operation because there is significant overhead 1.538 + * in the open and close. Also continually opening and closing the database 1.539 + * defeats the cache code as the cache table is lost on close (thus 1.540 + * requiring us to have to reinitialize the cache every operation). 1.541 + * 1.542 + * An execption to the shared handle is transations. All writes happen 1.543 + * through a transaction. When we are in a transaction, we must use the 1.544 + * same database pointer for that entire transation. In this case we save 1.545 + * the transaction database and use it for all accesses on the transaction 1.546 + * thread. Other threads use the common database. 1.547 + * 1.548 + * There can only be once active transaction on the database at a time. 1.549 + * 1.550 + * sdb_openDBLocal() provides us with a valid database handle for whatever 1.551 + * state we are in (reading or in a transaction), and acquires any locks 1.552 + * appropriate to that state. It also decides when it's time to refresh 1.553 + * the cache before we start an operation. Any database handle returned 1.554 + * just eventually be closed with sdb_closeDBLocal(). 1.555 + * 1.556 + * The table returned either points to the database's physical table, or 1.557 + * to the cached shadow. Tranactions always return the physical table 1.558 + * and read operations return either the physical table or the cache 1.559 + * depending on whether or not the cache exists. 1.560 + */ 1.561 +static CK_RV 1.562 +sdb_openDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB, const char **table) 1.563 +{ 1.564 + *sqlDB = NULL; 1.565 + 1.566 + PR_EnterMonitor(sdb_p->dbMon); 1.567 + 1.568 + if (table) { 1.569 + *table = sdb_p->table; 1.570 + } 1.571 + 1.572 + /* We're in a transaction, use the transaction DB */ 1.573 + if ((sdb_p->sqlXactDB) && (sdb_p->sqlXactThread == PR_GetCurrentThread())) { 1.574 + *sqlDB =sdb_p->sqlXactDB; 1.575 + /* only one thread can get here, safe to unlock */ 1.576 + PR_ExitMonitor(sdb_p->dbMon); 1.577 + return CKR_OK; 1.578 + } 1.579 + 1.580 + /* 1.581 + * if we are just reading from the table, we may have the table 1.582 + * cached in a temporary table (especially if it's on a shared FS). 1.583 + * In that case we want to see updates to the table, the the granularity 1.584 + * is on order of human scale, not computer scale. 1.585 + */ 1.586 + if (table && sdb_p->cacheTable) { 1.587 + PRIntervalTime now = PR_IntervalNow(); 1.588 + if ((now - sdb_p->lastUpdateTime) > sdb_p->updateInterval) { 1.589 + sdb_updateCache(sdb_p); 1.590 + } 1.591 + *table = sdb_p->cacheTable; 1.592 + } 1.593 + 1.594 + *sqlDB = sdb_p->sqlReadDB; 1.595 + 1.596 + /* leave holding the lock. only one thread can actually use a given 1.597 + * database connection at once */ 1.598 + 1.599 + return CKR_OK; 1.600 +} 1.601 + 1.602 +/* closing the local database currenly means unlocking the monitor */ 1.603 +static CK_RV 1.604 +sdb_closeDBLocal(SDBPrivate *sdb_p, sqlite3 *sqlDB) 1.605 +{ 1.606 + if (sdb_p->sqlXactDB != sqlDB) { 1.607 + /* if we weren't in a transaction, we got a lock */ 1.608 + PR_ExitMonitor(sdb_p->dbMon); 1.609 + } 1.610 + return CKR_OK; 1.611 +} 1.612 + 1.613 + 1.614 +/* 1.615 + * wrapper to sqlite3_open which also sets the busy_timeout 1.616 + */ 1.617 +static int 1.618 +sdb_openDB(const char *name, sqlite3 **sqlDB, int flags) 1.619 +{ 1.620 + int sqlerr; 1.621 + /* 1.622 + * in sqlite3 3.5.0, there is a new open call that allows us 1.623 + * to specify read only. Most new OS's are still on 3.3.x (including 1.624 + * NSS's internal version and the version shipped with Firefox). 1.625 + */ 1.626 + *sqlDB = NULL; 1.627 + sqlerr = sqlite3_open(name, sqlDB); 1.628 + if (sqlerr != SQLITE_OK) { 1.629 + return sqlerr; 1.630 + } 1.631 + 1.632 + sqlerr = sqlite3_busy_timeout(*sqlDB, SDB_SQLITE_BUSY_TIMEOUT); 1.633 + if (sqlerr != SQLITE_OK) { 1.634 + sqlite3_close(*sqlDB); 1.635 + *sqlDB = NULL; 1.636 + return sqlerr; 1.637 + } 1.638 + return SQLITE_OK; 1.639 +} 1.640 + 1.641 +/* Sigh, if we created a new table since we opened the database, 1.642 + * the database handle will not see the new table, we need to close this 1.643 + * database and reopen it. Caller must be in a transaction or holding 1.644 + * the dbMon. sqlDB is changed on success. */ 1.645 +static int 1.646 +sdb_reopenDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB) { 1.647 + sqlite3 *newDB; 1.648 + int sqlerr; 1.649 + 1.650 + /* open a new database */ 1.651 + sqlerr = sdb_openDB(sdb_p->sqlDBName, &newDB, SDB_RDONLY); 1.652 + if (sqlerr != SQLITE_OK) { 1.653 + return sqlerr; 1.654 + } 1.655 + 1.656 + /* if we are in a transaction, we may not be holding the monitor. 1.657 + * grab it before we update the transaction database. This is 1.658 + * safe since are using monitors. */ 1.659 + PR_EnterMonitor(sdb_p->dbMon); 1.660 + /* update our view of the database */ 1.661 + if (sdb_p->sqlReadDB == *sqlDB) { 1.662 + sdb_p->sqlReadDB = newDB; 1.663 + } else if (sdb_p->sqlXactDB == *sqlDB) { 1.664 + sdb_p->sqlXactDB = newDB; 1.665 + } 1.666 + PR_ExitMonitor(sdb_p->dbMon); 1.667 + 1.668 + /* close the old one */ 1.669 + sqlite3_close(*sqlDB); 1.670 + 1.671 + *sqlDB = newDB; 1.672 + return SQLITE_OK; 1.673 +} 1.674 + 1.675 +struct SDBFindStr { 1.676 + sqlite3 *sqlDB; 1.677 + sqlite3_stmt *findstmt; 1.678 +}; 1.679 + 1.680 + 1.681 +static const char FIND_OBJECTS_CMD[] = "SELECT ALL * FROM %s WHERE %s;"; 1.682 +static const char FIND_OBJECTS_ALL_CMD[] = "SELECT ALL * FROM %s;"; 1.683 +CK_RV 1.684 +sdb_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *template, CK_ULONG count, 1.685 + SDBFind **find) 1.686 +{ 1.687 + SDBPrivate *sdb_p = sdb->private; 1.688 + sqlite3 *sqlDB = NULL; 1.689 + const char *table; 1.690 + char *newStr, *findStr = NULL; 1.691 + sqlite3_stmt *findstmt = NULL; 1.692 + char *join=""; 1.693 + int sqlerr = SQLITE_OK; 1.694 + CK_RV error = CKR_OK; 1.695 + int i; 1.696 + 1.697 + LOCK_SQLITE() 1.698 + *find = NULL; 1.699 + error = sdb_openDBLocal(sdb_p, &sqlDB, &table); 1.700 + if (error != CKR_OK) { 1.701 + goto loser; 1.702 + } 1.703 + 1.704 + findStr = sqlite3_mprintf(""); 1.705 + for (i=0; findStr && i < count; i++) { 1.706 + newStr = sqlite3_mprintf("%s%sa%x=$DATA%d", findStr, join, 1.707 + template[i].type, i); 1.708 + join=" AND "; 1.709 + sqlite3_free(findStr); 1.710 + findStr = newStr; 1.711 + } 1.712 + 1.713 + if (findStr == NULL) { 1.714 + error = CKR_HOST_MEMORY; 1.715 + goto loser; 1.716 + } 1.717 + 1.718 + if (count == 0) { 1.719 + newStr = sqlite3_mprintf(FIND_OBJECTS_ALL_CMD, table); 1.720 + } else { 1.721 + newStr = sqlite3_mprintf(FIND_OBJECTS_CMD, table, findStr); 1.722 + } 1.723 + sqlite3_free(findStr); 1.724 + if (newStr == NULL) { 1.725 + error = CKR_HOST_MEMORY; 1.726 + goto loser; 1.727 + } 1.728 + sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &findstmt, NULL); 1.729 + sqlite3_free(newStr); 1.730 + for (i=0; sqlerr == SQLITE_OK && i < count; i++) { 1.731 + const void *blobData = template[i].pValue; 1.732 + unsigned int blobSize = template[i].ulValueLen; 1.733 + if (blobSize == 0) { 1.734 + blobSize = SQLITE_EXPLICIT_NULL_LEN; 1.735 + blobData = SQLITE_EXPLICIT_NULL; 1.736 + } 1.737 + sqlerr = sqlite3_bind_blob(findstmt, i+1, blobData, blobSize, 1.738 + SQLITE_TRANSIENT); 1.739 + } 1.740 + if (sqlerr == SQLITE_OK) { 1.741 + *find = PORT_New(SDBFind); 1.742 + if (*find == NULL) { 1.743 + error = CKR_HOST_MEMORY; 1.744 + goto loser; 1.745 + } 1.746 + (*find)->findstmt = findstmt; 1.747 + (*find)->sqlDB = sqlDB; 1.748 + UNLOCK_SQLITE() 1.749 + return CKR_OK; 1.750 + } 1.751 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.752 + 1.753 +loser: 1.754 + if (findstmt) { 1.755 + sqlite3_reset(findstmt); 1.756 + sqlite3_finalize(findstmt); 1.757 + } 1.758 + if (sqlDB) { 1.759 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.760 + } 1.761 + UNLOCK_SQLITE() 1.762 + return error; 1.763 +} 1.764 + 1.765 + 1.766 +CK_RV 1.767 +sdb_FindObjects(SDB *sdb, SDBFind *sdbFind, CK_OBJECT_HANDLE *object, 1.768 + CK_ULONG arraySize, CK_ULONG *count) 1.769 +{ 1.770 + SDBPrivate *sdb_p = sdb->private; 1.771 + sqlite3_stmt *stmt = sdbFind->findstmt; 1.772 + int sqlerr = SQLITE_OK; 1.773 + int retry = 0; 1.774 + 1.775 + *count = 0; 1.776 + 1.777 + if (arraySize == 0) { 1.778 + return CKR_OK; 1.779 + } 1.780 + LOCK_SQLITE() 1.781 + 1.782 + do { 1.783 + sqlerr = sqlite3_step(stmt); 1.784 + if (sqlerr == SQLITE_BUSY) { 1.785 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.786 + } 1.787 + if (sqlerr == SQLITE_ROW) { 1.788 + /* only care about the id */ 1.789 + *object++= sqlite3_column_int(stmt, 0); 1.790 + arraySize--; 1.791 + (*count)++; 1.792 + } 1.793 + } while (!sdb_done(sqlerr,&retry) && (arraySize > 0)); 1.794 + 1.795 + /* we only have some of the objects, there is probably more, 1.796 + * set the sqlerr to an OK value so we return CKR_OK */ 1.797 + if (sqlerr == SQLITE_ROW && arraySize == 0) { 1.798 + sqlerr = SQLITE_DONE; 1.799 + } 1.800 + UNLOCK_SQLITE() 1.801 + 1.802 + return sdb_mapSQLError(sdb_p->type, sqlerr); 1.803 +} 1.804 + 1.805 +CK_RV 1.806 +sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind) 1.807 +{ 1.808 + SDBPrivate *sdb_p = sdb->private; 1.809 + sqlite3_stmt *stmt = sdbFind->findstmt; 1.810 + sqlite3 *sqlDB = sdbFind->sqlDB; 1.811 + int sqlerr = SQLITE_OK; 1.812 + 1.813 + LOCK_SQLITE() 1.814 + if (stmt) { 1.815 + sqlite3_reset(stmt); 1.816 + sqlerr = sqlite3_finalize(stmt); 1.817 + } 1.818 + if (sqlDB) { 1.819 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.820 + } 1.821 + PORT_Free(sdbFind); 1.822 + 1.823 + UNLOCK_SQLITE() 1.824 + return sdb_mapSQLError(sdb_p->type, sqlerr); 1.825 +} 1.826 + 1.827 +static const char GET_ATTRIBUTE_CMD[] = "SELECT ALL %s FROM %s WHERE id=$ID;"; 1.828 +CK_RV 1.829 +sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id, 1.830 + CK_ATTRIBUTE *template, CK_ULONG count) 1.831 +{ 1.832 + SDBPrivate *sdb_p = sdb->private; 1.833 + sqlite3 *sqlDB = NULL; 1.834 + sqlite3_stmt *stmt = NULL; 1.835 + char *getStr = NULL; 1.836 + char *newStr = NULL; 1.837 + const char *table = NULL; 1.838 + int sqlerr = SQLITE_OK; 1.839 + CK_RV error = CKR_OK; 1.840 + int found = 0; 1.841 + int retry = 0; 1.842 + int i; 1.843 + 1.844 + 1.845 + /* open a new db if necessary */ 1.846 + error = sdb_openDBLocal(sdb_p, &sqlDB, &table); 1.847 + if (error != CKR_OK) { 1.848 + goto loser; 1.849 + } 1.850 + 1.851 + for (i=0; i < count; i++) { 1.852 + getStr = sqlite3_mprintf("a%x", template[i].type); 1.853 + 1.854 + if (getStr == NULL) { 1.855 + error = CKR_HOST_MEMORY; 1.856 + goto loser; 1.857 + } 1.858 + 1.859 + newStr = sqlite3_mprintf(GET_ATTRIBUTE_CMD, getStr, table); 1.860 + sqlite3_free(getStr); 1.861 + getStr = NULL; 1.862 + if (newStr == NULL) { 1.863 + error = CKR_HOST_MEMORY; 1.864 + goto loser; 1.865 + } 1.866 + 1.867 + sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); 1.868 + sqlite3_free(newStr); 1.869 + newStr = NULL; 1.870 + if (sqlerr == SQLITE_ERROR) { 1.871 + template[i].ulValueLen = -1; 1.872 + error = CKR_ATTRIBUTE_TYPE_INVALID; 1.873 + continue; 1.874 + } else if (sqlerr != SQLITE_OK) { goto loser; } 1.875 + 1.876 + sqlerr = sqlite3_bind_int(stmt, 1, object_id); 1.877 + if (sqlerr != SQLITE_OK) { goto loser; } 1.878 + 1.879 + do { 1.880 + sqlerr = sqlite3_step(stmt); 1.881 + if (sqlerr == SQLITE_BUSY) { 1.882 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.883 + } 1.884 + if (sqlerr == SQLITE_ROW) { 1.885 + int blobSize; 1.886 + const char *blobData; 1.887 + 1.888 + blobSize = sqlite3_column_bytes(stmt, 0); 1.889 + blobData = sqlite3_column_blob(stmt, 0); 1.890 + if (blobData == NULL) { 1.891 + template[i].ulValueLen = -1; 1.892 + error = CKR_ATTRIBUTE_TYPE_INVALID; 1.893 + break; 1.894 + } 1.895 + /* If the blob equals our explicit NULL value, then the 1.896 + * attribute is a NULL. */ 1.897 + if ((blobSize == SQLITE_EXPLICIT_NULL_LEN) && 1.898 + (PORT_Memcmp(blobData, SQLITE_EXPLICIT_NULL, 1.899 + SQLITE_EXPLICIT_NULL_LEN) == 0)) { 1.900 + blobSize = 0; 1.901 + } 1.902 + if (template[i].pValue) { 1.903 + if (template[i].ulValueLen < blobSize) { 1.904 + template[i].ulValueLen = -1; 1.905 + error = CKR_BUFFER_TOO_SMALL; 1.906 + break; 1.907 + } 1.908 + PORT_Memcpy(template[i].pValue, blobData, blobSize); 1.909 + } 1.910 + template[i].ulValueLen = blobSize; 1.911 + found = 1; 1.912 + } 1.913 + } while (!sdb_done(sqlerr,&retry)); 1.914 + sqlite3_reset(stmt); 1.915 + sqlite3_finalize(stmt); 1.916 + stmt = NULL; 1.917 + } 1.918 + 1.919 +loser: 1.920 + /* fix up the error if necessary */ 1.921 + if (error == CKR_OK) { 1.922 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.923 + if (!found && error == CKR_OK) { 1.924 + error = CKR_OBJECT_HANDLE_INVALID; 1.925 + } 1.926 + } 1.927 + 1.928 + if (stmt) { 1.929 + sqlite3_reset(stmt); 1.930 + sqlite3_finalize(stmt); 1.931 + } 1.932 + 1.933 + /* if we had to open a new database, free it now */ 1.934 + if (sqlDB) { 1.935 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.936 + } 1.937 + return error; 1.938 +} 1.939 + 1.940 +CK_RV 1.941 +sdb_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, 1.942 + CK_ATTRIBUTE *template, CK_ULONG count) 1.943 +{ 1.944 + CK_RV crv; 1.945 + 1.946 + if (count == 0) { 1.947 + return CKR_OK; 1.948 + } 1.949 + 1.950 + LOCK_SQLITE() 1.951 + crv = sdb_GetAttributeValueNoLock(sdb, object_id, template, count); 1.952 + UNLOCK_SQLITE() 1.953 + return crv; 1.954 +} 1.955 + 1.956 +static const char SET_ATTRIBUTE_CMD[] = "UPDATE %s SET %s WHERE id=$ID;"; 1.957 +CK_RV 1.958 +sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id, 1.959 + const CK_ATTRIBUTE *template, CK_ULONG count) 1.960 +{ 1.961 + SDBPrivate *sdb_p = sdb->private; 1.962 + sqlite3 *sqlDB = NULL; 1.963 + sqlite3_stmt *stmt = NULL; 1.964 + char *setStr = NULL; 1.965 + char *newStr = NULL; 1.966 + int sqlerr = SQLITE_OK; 1.967 + int retry = 0; 1.968 + CK_RV error = CKR_OK; 1.969 + int i; 1.970 + 1.971 + if ((sdb->sdb_flags & SDB_RDONLY) != 0) { 1.972 + return CKR_TOKEN_WRITE_PROTECTED; 1.973 + } 1.974 + 1.975 + if (count == 0) { 1.976 + return CKR_OK; 1.977 + } 1.978 + 1.979 + LOCK_SQLITE() 1.980 + setStr = sqlite3_mprintf(""); 1.981 + for (i=0; setStr && i < count; i++) { 1.982 + if (i==0) { 1.983 + sqlite3_free(setStr); 1.984 + setStr = sqlite3_mprintf("a%x=$VALUE%d", 1.985 + template[i].type, i); 1.986 + continue; 1.987 + } 1.988 + newStr = sqlite3_mprintf("%s,a%x=$VALUE%d", setStr, 1.989 + template[i].type, i); 1.990 + sqlite3_free(setStr); 1.991 + setStr = newStr; 1.992 + } 1.993 + newStr = NULL; 1.994 + 1.995 + if (setStr == NULL) { 1.996 + return CKR_HOST_MEMORY; 1.997 + } 1.998 + newStr = sqlite3_mprintf(SET_ATTRIBUTE_CMD, sdb_p->table, setStr); 1.999 + sqlite3_free(setStr); 1.1000 + if (newStr == NULL) { 1.1001 + UNLOCK_SQLITE() 1.1002 + return CKR_HOST_MEMORY; 1.1003 + } 1.1004 + error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); 1.1005 + if (error != CKR_OK) { 1.1006 + goto loser; 1.1007 + } 1.1008 + sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); 1.1009 + if (sqlerr != SQLITE_OK) goto loser; 1.1010 + for (i=0; i < count; i++) { 1.1011 + if (template[i].ulValueLen != 0) { 1.1012 + sqlerr = sqlite3_bind_blob(stmt, i+1, template[i].pValue, 1.1013 + template[i].ulValueLen, SQLITE_STATIC); 1.1014 + } else { 1.1015 + sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL, 1.1016 + SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); 1.1017 + } 1.1018 + if (sqlerr != SQLITE_OK) goto loser; 1.1019 + } 1.1020 + sqlerr = sqlite3_bind_int(stmt, i+1, object_id); 1.1021 + if (sqlerr != SQLITE_OK) goto loser; 1.1022 + 1.1023 + do { 1.1024 + sqlerr = sqlite3_step(stmt); 1.1025 + if (sqlerr == SQLITE_BUSY) { 1.1026 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.1027 + } 1.1028 + } while (!sdb_done(sqlerr,&retry)); 1.1029 + 1.1030 +loser: 1.1031 + if (newStr) { 1.1032 + sqlite3_free(newStr); 1.1033 + } 1.1034 + if (error == CKR_OK) { 1.1035 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1036 + } 1.1037 + 1.1038 + if (stmt) { 1.1039 + sqlite3_reset(stmt); 1.1040 + sqlite3_finalize(stmt); 1.1041 + } 1.1042 + 1.1043 + if (sqlDB) { 1.1044 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.1045 + } 1.1046 + 1.1047 + UNLOCK_SQLITE() 1.1048 + return error; 1.1049 +} 1.1050 + 1.1051 +/* 1.1052 + * check to see if a candidate object handle already exists. 1.1053 + */ 1.1054 +static PRBool 1.1055 +sdb_objectExists(SDB *sdb, CK_OBJECT_HANDLE candidate) 1.1056 +{ 1.1057 + CK_RV crv; 1.1058 + CK_ATTRIBUTE template = { CKA_LABEL, NULL, 0 }; 1.1059 + 1.1060 + crv = sdb_GetAttributeValueNoLock(sdb,candidate,&template, 1); 1.1061 + if (crv == CKR_OBJECT_HANDLE_INVALID) { 1.1062 + return PR_FALSE; 1.1063 + } 1.1064 + return PR_TRUE; 1.1065 +} 1.1066 + 1.1067 +/* 1.1068 + * if we're here, we are in a transaction, so it's safe 1.1069 + * to examine the current state of the database 1.1070 + */ 1.1071 +static CK_OBJECT_HANDLE 1.1072 +sdb_getObjectId(SDB *sdb) 1.1073 +{ 1.1074 + CK_OBJECT_HANDLE candidate; 1.1075 + static CK_OBJECT_HANDLE next_obj = CK_INVALID_HANDLE; 1.1076 + int count; 1.1077 + /* 1.1078 + * get an initial object handle to use 1.1079 + */ 1.1080 + if (next_obj == CK_INVALID_HANDLE) { 1.1081 + PRTime time; 1.1082 + time = PR_Now(); 1.1083 + 1.1084 + next_obj = (CK_OBJECT_HANDLE)(time & 0x3fffffffL); 1.1085 + } 1.1086 + candidate = next_obj++; 1.1087 + /* detect that we've looped through all the handles... */ 1.1088 + for (count = 0; count < 0x40000000; count++, candidate = next_obj++) { 1.1089 + /* mask off excess bits */ 1.1090 + candidate &= 0x3fffffff; 1.1091 + /* if we hit zero, go to the next entry */ 1.1092 + if (candidate == CK_INVALID_HANDLE) { 1.1093 + continue; 1.1094 + } 1.1095 + /* make sure we aren't already using */ 1.1096 + if (!sdb_objectExists(sdb, candidate)) { 1.1097 + /* this one is free */ 1.1098 + return candidate; 1.1099 + } 1.1100 + } 1.1101 + 1.1102 + /* no handle is free, fail */ 1.1103 + return CK_INVALID_HANDLE; 1.1104 +} 1.1105 + 1.1106 +static const char CREATE_CMD[] = "INSERT INTO %s (id%s) VALUES($ID%s);"; 1.1107 +CK_RV 1.1108 +sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id, 1.1109 + const CK_ATTRIBUTE *template, CK_ULONG count) 1.1110 +{ 1.1111 + SDBPrivate *sdb_p = sdb->private; 1.1112 + sqlite3 *sqlDB = NULL; 1.1113 + sqlite3_stmt *stmt = NULL; 1.1114 + char *columnStr = NULL; 1.1115 + char *valueStr = NULL; 1.1116 + char *newStr = NULL; 1.1117 + int sqlerr = SQLITE_OK; 1.1118 + CK_RV error = CKR_OK; 1.1119 + CK_OBJECT_HANDLE this_object = CK_INVALID_HANDLE; 1.1120 + int retry = 0; 1.1121 + int i; 1.1122 + 1.1123 + if ((sdb->sdb_flags & SDB_RDONLY) != 0) { 1.1124 + return CKR_TOKEN_WRITE_PROTECTED; 1.1125 + } 1.1126 + 1.1127 + LOCK_SQLITE() 1.1128 + if ((*object_id != CK_INVALID_HANDLE) && 1.1129 + !sdb_objectExists(sdb, *object_id)) { 1.1130 + this_object = *object_id; 1.1131 + } else { 1.1132 + this_object = sdb_getObjectId(sdb); 1.1133 + } 1.1134 + if (this_object == CK_INVALID_HANDLE) { 1.1135 + UNLOCK_SQLITE(); 1.1136 + return CKR_HOST_MEMORY; 1.1137 + } 1.1138 + columnStr = sqlite3_mprintf(""); 1.1139 + valueStr = sqlite3_mprintf(""); 1.1140 + *object_id = this_object; 1.1141 + for (i=0; columnStr && valueStr && i < count; i++) { 1.1142 + newStr = sqlite3_mprintf("%s,a%x", columnStr, template[i].type); 1.1143 + sqlite3_free(columnStr); 1.1144 + columnStr = newStr; 1.1145 + newStr = sqlite3_mprintf("%s,$VALUE%d", valueStr, i); 1.1146 + sqlite3_free(valueStr); 1.1147 + valueStr = newStr; 1.1148 + } 1.1149 + newStr = NULL; 1.1150 + if ((columnStr == NULL) || (valueStr == NULL)) { 1.1151 + if (columnStr) { 1.1152 + sqlite3_free(columnStr); 1.1153 + } 1.1154 + if (valueStr) { 1.1155 + sqlite3_free(valueStr); 1.1156 + } 1.1157 + UNLOCK_SQLITE() 1.1158 + return CKR_HOST_MEMORY; 1.1159 + } 1.1160 + newStr = sqlite3_mprintf(CREATE_CMD, sdb_p->table, columnStr, valueStr); 1.1161 + sqlite3_free(columnStr); 1.1162 + sqlite3_free(valueStr); 1.1163 + error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); 1.1164 + if (error != CKR_OK) { 1.1165 + goto loser; 1.1166 + } 1.1167 + sqlerr = sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); 1.1168 + if (sqlerr != SQLITE_OK) goto loser; 1.1169 + sqlerr = sqlite3_bind_int(stmt, 1, *object_id); 1.1170 + if (sqlerr != SQLITE_OK) goto loser; 1.1171 + for (i=0; i < count; i++) { 1.1172 + if (template[i].ulValueLen) { 1.1173 + sqlerr = sqlite3_bind_blob(stmt, i+2, template[i].pValue, 1.1174 + template[i].ulValueLen, SQLITE_STATIC); 1.1175 + } else { 1.1176 + sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL, 1.1177 + SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC); 1.1178 + } 1.1179 + if (sqlerr != SQLITE_OK) goto loser; 1.1180 + } 1.1181 + 1.1182 + do { 1.1183 + sqlerr = sqlite3_step(stmt); 1.1184 + if (sqlerr == SQLITE_BUSY) { 1.1185 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.1186 + } 1.1187 + } while (!sdb_done(sqlerr,&retry)); 1.1188 + 1.1189 +loser: 1.1190 + if (newStr) { 1.1191 + sqlite3_free(newStr); 1.1192 + } 1.1193 + if (error == CKR_OK) { 1.1194 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1195 + } 1.1196 + 1.1197 + if (stmt) { 1.1198 + sqlite3_reset(stmt); 1.1199 + sqlite3_finalize(stmt); 1.1200 + } 1.1201 + 1.1202 + if (sqlDB) { 1.1203 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.1204 + } 1.1205 + UNLOCK_SQLITE() 1.1206 + 1.1207 + return error; 1.1208 +} 1.1209 + 1.1210 +static const char DESTROY_CMD[] = "DELETE FROM %s WHERE (id=$ID);"; 1.1211 +CK_RV 1.1212 +sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id) 1.1213 +{ 1.1214 + SDBPrivate *sdb_p = sdb->private; 1.1215 + sqlite3 *sqlDB = NULL; 1.1216 + sqlite3_stmt *stmt = NULL; 1.1217 + char *newStr = NULL; 1.1218 + int sqlerr = SQLITE_OK; 1.1219 + CK_RV error = CKR_OK; 1.1220 + int retry = 0; 1.1221 + 1.1222 + if ((sdb->sdb_flags & SDB_RDONLY) != 0) { 1.1223 + return CKR_TOKEN_WRITE_PROTECTED; 1.1224 + } 1.1225 + 1.1226 + LOCK_SQLITE() 1.1227 + error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); 1.1228 + if (error != CKR_OK) { 1.1229 + goto loser; 1.1230 + } 1.1231 + newStr = sqlite3_mprintf(DESTROY_CMD, sdb_p->table); 1.1232 + if (newStr == NULL) { 1.1233 + error = CKR_HOST_MEMORY; 1.1234 + goto loser; 1.1235 + } 1.1236 + sqlerr =sqlite3_prepare_v2(sqlDB, newStr, -1, &stmt, NULL); 1.1237 + sqlite3_free(newStr); 1.1238 + if (sqlerr != SQLITE_OK) goto loser; 1.1239 + sqlerr =sqlite3_bind_int(stmt, 1, object_id); 1.1240 + if (sqlerr != SQLITE_OK) goto loser; 1.1241 + 1.1242 + do { 1.1243 + sqlerr = sqlite3_step(stmt); 1.1244 + if (sqlerr == SQLITE_BUSY) { 1.1245 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.1246 + } 1.1247 + } while (!sdb_done(sqlerr,&retry)); 1.1248 + 1.1249 +loser: 1.1250 + if (error == CKR_OK) { 1.1251 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1252 + } 1.1253 + 1.1254 + if (stmt) { 1.1255 + sqlite3_reset(stmt); 1.1256 + sqlite3_finalize(stmt); 1.1257 + } 1.1258 + 1.1259 + if (sqlDB) { 1.1260 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.1261 + } 1.1262 + 1.1263 + UNLOCK_SQLITE() 1.1264 + return error; 1.1265 +} 1.1266 + 1.1267 +static const char BEGIN_CMD[] = "BEGIN IMMEDIATE TRANSACTION;"; 1.1268 +/* 1.1269 + * start a transaction. 1.1270 + * 1.1271 + * We need to open a new database, then store that new database into 1.1272 + * the private data structure. We open the database first, then use locks 1.1273 + * to protect storing the data to prevent deadlocks. 1.1274 + */ 1.1275 +CK_RV 1.1276 +sdb_Begin(SDB *sdb) 1.1277 +{ 1.1278 + SDBPrivate *sdb_p = sdb->private; 1.1279 + sqlite3 *sqlDB = NULL; 1.1280 + sqlite3_stmt *stmt = NULL; 1.1281 + int sqlerr = SQLITE_OK; 1.1282 + CK_RV error = CKR_OK; 1.1283 + int retry = 0; 1.1284 + 1.1285 + 1.1286 + if ((sdb->sdb_flags & SDB_RDONLY) != 0) { 1.1287 + return CKR_TOKEN_WRITE_PROTECTED; 1.1288 + } 1.1289 + 1.1290 + 1.1291 + LOCK_SQLITE() 1.1292 + 1.1293 + /* get a new version that we will use for the entire transaction */ 1.1294 + sqlerr = sdb_openDB(sdb_p->sqlDBName, &sqlDB, SDB_RDWR); 1.1295 + if (sqlerr != SQLITE_OK) { 1.1296 + goto loser; 1.1297 + } 1.1298 + 1.1299 + sqlerr =sqlite3_prepare_v2(sqlDB, BEGIN_CMD, -1, &stmt, NULL); 1.1300 + 1.1301 + do { 1.1302 + sqlerr = sqlite3_step(stmt); 1.1303 + if (sqlerr == SQLITE_BUSY) { 1.1304 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.1305 + } 1.1306 + } while (!sdb_done(sqlerr,&retry)); 1.1307 + 1.1308 + if (stmt) { 1.1309 + sqlite3_reset(stmt); 1.1310 + sqlite3_finalize(stmt); 1.1311 + } 1.1312 + 1.1313 +loser: 1.1314 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1315 + 1.1316 + /* we are starting a new transaction, 1.1317 + * and if we succeeded, then save this database for the rest of 1.1318 + * our transaction */ 1.1319 + if (error == CKR_OK) { 1.1320 + /* we hold a 'BEGIN TRANSACTION' and a sdb_p->lock. At this point 1.1321 + * sdb_p->sqlXactDB MUST be null */ 1.1322 + PR_EnterMonitor(sdb_p->dbMon); 1.1323 + PORT_Assert(sdb_p->sqlXactDB == NULL); 1.1324 + sdb_p->sqlXactDB = sqlDB; 1.1325 + sdb_p->sqlXactThread = PR_GetCurrentThread(); 1.1326 + PR_ExitMonitor(sdb_p->dbMon); 1.1327 + } else { 1.1328 + /* we failed to start our transaction, 1.1329 + * free any databases we opened. */ 1.1330 + if (sqlDB) { 1.1331 + sqlite3_close(sqlDB); 1.1332 + } 1.1333 + } 1.1334 + 1.1335 + UNLOCK_SQLITE() 1.1336 + return error; 1.1337 +} 1.1338 + 1.1339 +/* 1.1340 + * Complete a transaction. Basically undo everything we did in begin. 1.1341 + * There are 2 flavors Abort and Commit. Basically the only differerence between 1.1342 + * these 2 are what the database will show. (no change in to former, change in 1.1343 + * the latter). 1.1344 + */ 1.1345 +static CK_RV 1.1346 +sdb_complete(SDB *sdb, const char *cmd) 1.1347 +{ 1.1348 + SDBPrivate *sdb_p = sdb->private; 1.1349 + sqlite3 *sqlDB = NULL; 1.1350 + sqlite3_stmt *stmt = NULL; 1.1351 + int sqlerr = SQLITE_OK; 1.1352 + CK_RV error = CKR_OK; 1.1353 + int retry = 0; 1.1354 + 1.1355 + 1.1356 + if ((sdb->sdb_flags & SDB_RDONLY) != 0) { 1.1357 + return CKR_TOKEN_WRITE_PROTECTED; 1.1358 + } 1.1359 + 1.1360 + /* We must have a transation database, or we shouldn't have arrived here */ 1.1361 + PR_EnterMonitor(sdb_p->dbMon); 1.1362 + PORT_Assert(sdb_p->sqlXactDB); 1.1363 + if (sdb_p->sqlXactDB == NULL) { 1.1364 + PR_ExitMonitor(sdb_p->dbMon); 1.1365 + return CKR_GENERAL_ERROR; /* shouldn't happen */ 1.1366 + } 1.1367 + PORT_Assert( sdb_p->sqlXactThread == PR_GetCurrentThread()); 1.1368 + if ( sdb_p->sqlXactThread != PR_GetCurrentThread()) { 1.1369 + PR_ExitMonitor(sdb_p->dbMon); 1.1370 + return CKR_GENERAL_ERROR; /* shouldn't happen */ 1.1371 + } 1.1372 + sqlDB = sdb_p->sqlXactDB; 1.1373 + sdb_p->sqlXactDB = NULL; /* no one else can get to this DB, 1.1374 + * safe to unlock */ 1.1375 + sdb_p->sqlXactThread = NULL; 1.1376 + PR_ExitMonitor(sdb_p->dbMon); 1.1377 + 1.1378 + sqlerr =sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL); 1.1379 + 1.1380 + do { 1.1381 + sqlerr = sqlite3_step(stmt); 1.1382 + if (sqlerr == SQLITE_BUSY) { 1.1383 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.1384 + } 1.1385 + } while (!sdb_done(sqlerr,&retry)); 1.1386 + 1.1387 + /* Pending BEGIN TRANSACTIONS Can move forward at this point. */ 1.1388 + 1.1389 + if (stmt) { 1.1390 + sqlite3_reset(stmt); 1.1391 + sqlite3_finalize(stmt); 1.1392 + } 1.1393 + 1.1394 + /* we we have a cached DB image, update it as well */ 1.1395 + if (sdb_p->cacheTable) { 1.1396 + PR_EnterMonitor(sdb_p->dbMon); 1.1397 + sdb_updateCache(sdb_p); 1.1398 + PR_ExitMonitor(sdb_p->dbMon); 1.1399 + } 1.1400 + 1.1401 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1402 + 1.1403 + /* We just finished a transaction. 1.1404 + * Free the database, and remove it from the list */ 1.1405 + sqlite3_close(sqlDB); 1.1406 + 1.1407 + return error; 1.1408 +} 1.1409 + 1.1410 +static const char COMMIT_CMD[] = "COMMIT TRANSACTION;"; 1.1411 +CK_RV 1.1412 +sdb_Commit(SDB *sdb) 1.1413 +{ 1.1414 + CK_RV crv; 1.1415 + LOCK_SQLITE() 1.1416 + crv = sdb_complete(sdb,COMMIT_CMD); 1.1417 + UNLOCK_SQLITE() 1.1418 + return crv; 1.1419 +} 1.1420 + 1.1421 +static const char ROLLBACK_CMD[] = "ROLLBACK TRANSACTION;"; 1.1422 +CK_RV 1.1423 +sdb_Abort(SDB *sdb) 1.1424 +{ 1.1425 + CK_RV crv; 1.1426 + LOCK_SQLITE() 1.1427 + crv = sdb_complete(sdb,ROLLBACK_CMD); 1.1428 + UNLOCK_SQLITE() 1.1429 + return crv; 1.1430 +} 1.1431 + 1.1432 +static int tableExists(sqlite3 *sqlDB, const char *tableName); 1.1433 + 1.1434 +static const char GET_PW_CMD[] = "SELECT ALL * FROM metaData WHERE id=$ID;"; 1.1435 +CK_RV 1.1436 +sdb_GetMetaData(SDB *sdb, const char *id, SECItem *item1, SECItem *item2) 1.1437 +{ 1.1438 + SDBPrivate *sdb_p = sdb->private; 1.1439 + sqlite3 *sqlDB = sdb_p->sqlXactDB; 1.1440 + sqlite3_stmt *stmt = NULL; 1.1441 + int sqlerr = SQLITE_OK; 1.1442 + CK_RV error = CKR_OK; 1.1443 + int found = 0; 1.1444 + int retry = 0; 1.1445 + 1.1446 + LOCK_SQLITE() 1.1447 + error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); 1.1448 + if (error != CKR_OK) { 1.1449 + goto loser; 1.1450 + } 1.1451 + 1.1452 + /* handle 'test' versions of the sqlite db */ 1.1453 + sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL); 1.1454 + /* Sigh, if we created a new table since we opened the database, 1.1455 + * the database handle will not see the new table, we need to close this 1.1456 + * database and reopen it. This is safe because we are holding the lock 1.1457 + * still. */ 1.1458 + if (sqlerr == SQLITE_SCHEMA) { 1.1459 + sqlerr = sdb_reopenDBLocal(sdb_p, &sqlDB); 1.1460 + if (sqlerr != SQLITE_OK) { 1.1461 + goto loser; 1.1462 + } 1.1463 + sqlerr = sqlite3_prepare_v2(sqlDB, GET_PW_CMD, -1, &stmt, NULL); 1.1464 + } 1.1465 + if (sqlerr != SQLITE_OK) goto loser; 1.1466 + sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC); 1.1467 + do { 1.1468 + sqlerr = sqlite3_step(stmt); 1.1469 + if (sqlerr == SQLITE_BUSY) { 1.1470 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.1471 + } 1.1472 + if (sqlerr == SQLITE_ROW) { 1.1473 + const char *blobData; 1.1474 + unsigned int len = item1->len; 1.1475 + item1->len = sqlite3_column_bytes(stmt, 1); 1.1476 + if (item1->len > len) { 1.1477 + error = CKR_BUFFER_TOO_SMALL; 1.1478 + continue; 1.1479 + } 1.1480 + blobData = sqlite3_column_blob(stmt, 1); 1.1481 + PORT_Memcpy(item1->data,blobData, item1->len); 1.1482 + if (item2) { 1.1483 + len = item2->len; 1.1484 + item2->len = sqlite3_column_bytes(stmt, 2); 1.1485 + if (item2->len > len) { 1.1486 + error = CKR_BUFFER_TOO_SMALL; 1.1487 + continue; 1.1488 + } 1.1489 + blobData = sqlite3_column_blob(stmt, 2); 1.1490 + PORT_Memcpy(item2->data,blobData, item2->len); 1.1491 + } 1.1492 + found = 1; 1.1493 + } 1.1494 + } while (!sdb_done(sqlerr,&retry)); 1.1495 + 1.1496 +loser: 1.1497 + /* fix up the error if necessary */ 1.1498 + if (error == CKR_OK) { 1.1499 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1500 + if (!found && error == CKR_OK) { 1.1501 + error = CKR_OBJECT_HANDLE_INVALID; 1.1502 + } 1.1503 + } 1.1504 + 1.1505 + if (stmt) { 1.1506 + sqlite3_reset(stmt); 1.1507 + sqlite3_finalize(stmt); 1.1508 + } 1.1509 + 1.1510 + if (sqlDB) { 1.1511 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.1512 + } 1.1513 + UNLOCK_SQLITE() 1.1514 + 1.1515 + return error; 1.1516 +} 1.1517 + 1.1518 +static const char PW_CREATE_TABLE_CMD[] = 1.1519 + "CREATE TABLE metaData (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, item1, item2);"; 1.1520 +static const char PW_CREATE_CMD[] = 1.1521 + "INSERT INTO metaData (id,item1,item2) VALUES($ID,$ITEM1,$ITEM2);"; 1.1522 +static const char MD_CREATE_CMD[] = 1.1523 + "INSERT INTO metaData (id,item1) VALUES($ID,$ITEM1);"; 1.1524 +CK_RV 1.1525 +sdb_PutMetaData(SDB *sdb, const char *id, const SECItem *item1, 1.1526 + const SECItem *item2) 1.1527 +{ 1.1528 + SDBPrivate *sdb_p = sdb->private; 1.1529 + sqlite3 *sqlDB = sdb_p->sqlXactDB; 1.1530 + sqlite3_stmt *stmt = NULL; 1.1531 + int sqlerr = SQLITE_OK; 1.1532 + CK_RV error = CKR_OK; 1.1533 + int retry = 0; 1.1534 + const char *cmd = PW_CREATE_CMD; 1.1535 + 1.1536 + if ((sdb->sdb_flags & SDB_RDONLY) != 0) { 1.1537 + return CKR_TOKEN_WRITE_PROTECTED; 1.1538 + } 1.1539 + 1.1540 + LOCK_SQLITE() 1.1541 + error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); 1.1542 + if (error != CKR_OK) { 1.1543 + goto loser; 1.1544 + } 1.1545 + 1.1546 + if (!tableExists(sqlDB, "metaData")) { 1.1547 + sqlerr = sqlite3_exec(sqlDB, PW_CREATE_TABLE_CMD, NULL, 0, NULL); 1.1548 + if (sqlerr != SQLITE_OK) goto loser; 1.1549 + } 1.1550 + if (item2 == NULL) { 1.1551 + cmd = MD_CREATE_CMD; 1.1552 + } 1.1553 + sqlerr = sqlite3_prepare_v2(sqlDB, cmd, -1, &stmt, NULL); 1.1554 + if (sqlerr != SQLITE_OK) goto loser; 1.1555 + sqlerr = sqlite3_bind_text(stmt, 1, id, PORT_Strlen(id), SQLITE_STATIC); 1.1556 + if (sqlerr != SQLITE_OK) goto loser; 1.1557 + sqlerr = sqlite3_bind_blob(stmt, 2, item1->data, item1->len, SQLITE_STATIC); 1.1558 + if (sqlerr != SQLITE_OK) goto loser; 1.1559 + if (item2) { 1.1560 + sqlerr = sqlite3_bind_blob(stmt, 3, item2->data, 1.1561 + item2->len, SQLITE_STATIC); 1.1562 + if (sqlerr != SQLITE_OK) goto loser; 1.1563 + } 1.1564 + 1.1565 + do { 1.1566 + sqlerr = sqlite3_step(stmt); 1.1567 + if (sqlerr == SQLITE_BUSY) { 1.1568 + PR_Sleep(SDB_BUSY_RETRY_TIME); 1.1569 + } 1.1570 + } while (!sdb_done(sqlerr,&retry)); 1.1571 + 1.1572 +loser: 1.1573 + /* fix up the error if necessary */ 1.1574 + if (error == CKR_OK) { 1.1575 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1576 + } 1.1577 + 1.1578 + if (stmt) { 1.1579 + sqlite3_reset(stmt); 1.1580 + sqlite3_finalize(stmt); 1.1581 + } 1.1582 + 1.1583 + if (sqlDB) { 1.1584 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.1585 + } 1.1586 + UNLOCK_SQLITE() 1.1587 + 1.1588 + return error; 1.1589 +} 1.1590 + 1.1591 +static const char RESET_CMD[] = "DROP TABLE IF EXISTS %s;"; 1.1592 +CK_RV 1.1593 +sdb_Reset(SDB *sdb) 1.1594 +{ 1.1595 + SDBPrivate *sdb_p = sdb->private; 1.1596 + sqlite3 *sqlDB = NULL; 1.1597 + char *newStr; 1.1598 + int sqlerr = SQLITE_OK; 1.1599 + CK_RV error = CKR_OK; 1.1600 + 1.1601 + /* only Key databases can be reset */ 1.1602 + if (sdb_p->type != SDB_KEY) { 1.1603 + return CKR_OBJECT_HANDLE_INVALID; 1.1604 + } 1.1605 + 1.1606 + LOCK_SQLITE() 1.1607 + error = sdb_openDBLocal(sdb_p, &sqlDB, NULL); 1.1608 + if (error != CKR_OK) { 1.1609 + goto loser; 1.1610 + } 1.1611 + 1.1612 + /* delete the key table */ 1.1613 + newStr = sqlite3_mprintf(RESET_CMD, sdb_p->table); 1.1614 + if (newStr == NULL) { 1.1615 + error = CKR_HOST_MEMORY; 1.1616 + goto loser; 1.1617 + } 1.1618 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.1619 + sqlite3_free(newStr); 1.1620 + 1.1621 + if (sqlerr != SQLITE_OK) goto loser; 1.1622 + 1.1623 + /* delete the password entry table */ 1.1624 + sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS metaData;", 1.1625 + NULL, 0, NULL); 1.1626 + 1.1627 +loser: 1.1628 + /* fix up the error if necessary */ 1.1629 + if (error == CKR_OK) { 1.1630 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1631 + } 1.1632 + 1.1633 + if (sqlDB) { 1.1634 + sdb_closeDBLocal(sdb_p, sqlDB) ; 1.1635 + } 1.1636 + 1.1637 + UNLOCK_SQLITE() 1.1638 + return error; 1.1639 +} 1.1640 + 1.1641 + 1.1642 +CK_RV 1.1643 +sdb_Close(SDB *sdb) 1.1644 +{ 1.1645 + SDBPrivate *sdb_p = sdb->private; 1.1646 + int sqlerr = SQLITE_OK; 1.1647 + sdbDataType type = sdb_p->type; 1.1648 + 1.1649 + sqlerr = sqlite3_close(sdb_p->sqlReadDB); 1.1650 + PORT_Free(sdb_p->sqlDBName); 1.1651 + if (sdb_p->cacheTable) { 1.1652 + sqlite3_free(sdb_p->cacheTable); 1.1653 + } 1.1654 + if (sdb_p->dbMon) { 1.1655 + PR_DestroyMonitor(sdb_p->dbMon); 1.1656 + } 1.1657 + free(sdb_p); 1.1658 + free(sdb); 1.1659 + return sdb_mapSQLError(type, sqlerr); 1.1660 +} 1.1661 + 1.1662 + 1.1663 +/* 1.1664 + * functions to support open 1.1665 + */ 1.1666 + 1.1667 +static const char CHECK_TABLE_CMD[] = "SELECT ALL * FROM %s LIMIT 0;"; 1.1668 +/* return 1 if sqlDB contains table 'tableName */ 1.1669 +static int tableExists(sqlite3 *sqlDB, const char *tableName) 1.1670 +{ 1.1671 + char * cmd = sqlite3_mprintf(CHECK_TABLE_CMD, tableName); 1.1672 + int sqlerr = SQLITE_OK; 1.1673 + 1.1674 + if (cmd == NULL) { 1.1675 + return 0; 1.1676 + } 1.1677 + 1.1678 + sqlerr = sqlite3_exec(sqlDB, cmd, NULL, 0, 0); 1.1679 + sqlite3_free(cmd); 1.1680 + 1.1681 + return (sqlerr == SQLITE_OK) ? 1 : 0; 1.1682 +} 1.1683 + 1.1684 +void sdb_SetForkState(PRBool forked) 1.1685 +{ 1.1686 + /* XXXright now this is a no-op. The global fork state in the softokn3 1.1687 + * shared library is already taken care of at the PKCS#11 level. 1.1688 + * If and when we add fork state to the sqlite shared library and extern 1.1689 + * interface, we will need to set it and reset it from here */ 1.1690 +} 1.1691 + 1.1692 +/* 1.1693 + * initialize a single database 1.1694 + */ 1.1695 +static const char INIT_CMD[] = 1.1696 + "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)"; 1.1697 +static const char ALTER_CMD[] = 1.1698 + "ALTER TABLE %s ADD COLUMN a%x"; 1.1699 + 1.1700 +CK_RV 1.1701 +sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, 1.1702 + int *newInit, int flags, PRUint32 accessOps, SDB **pSdb) 1.1703 +{ 1.1704 + int i; 1.1705 + char *initStr = NULL; 1.1706 + char *newStr; 1.1707 + int inTransaction = 0; 1.1708 + SDB *sdb = NULL; 1.1709 + SDBPrivate *sdb_p = NULL; 1.1710 + sqlite3 *sqlDB = NULL; 1.1711 + int sqlerr = SQLITE_OK; 1.1712 + CK_RV error = CKR_OK; 1.1713 + char *cacheTable = NULL; 1.1714 + PRIntervalTime now = 0; 1.1715 + char *env; 1.1716 + PRBool enableCache = PR_FALSE; 1.1717 + PRBool create; 1.1718 + 1.1719 + *pSdb = NULL; 1.1720 + *inUpdate = 0; 1.1721 + 1.1722 + /* sqlite3 doesn't have a flag to specify that we want to 1.1723 + * open the database read only. If the db doesn't exist, 1.1724 + * sqlite3 will always create it. 1.1725 + */ 1.1726 + LOCK_SQLITE(); 1.1727 + create = (PR_Access(dbname, PR_ACCESS_EXISTS) != PR_SUCCESS); 1.1728 + if ((flags == SDB_RDONLY) && create) { 1.1729 + error = sdb_mapSQLError(type, SQLITE_CANTOPEN); 1.1730 + goto loser; 1.1731 + } 1.1732 + sqlerr = sdb_openDB(dbname, &sqlDB, flags); 1.1733 + if (sqlerr != SQLITE_OK) { 1.1734 + error = sdb_mapSQLError(type, sqlerr); 1.1735 + goto loser; 1.1736 + } 1.1737 + /* sql created the file, but it doesn't set appropriate modes for 1.1738 + * a database */ 1.1739 + if (create) { 1.1740 + /* NO NSPR call for this? :( */ 1.1741 + chmod (dbname, 0600); 1.1742 + } 1.1743 + 1.1744 + if (flags != SDB_RDONLY) { 1.1745 + sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL); 1.1746 + if (sqlerr != SQLITE_OK) { 1.1747 + error = sdb_mapSQLError(type, sqlerr); 1.1748 + goto loser; 1.1749 + } 1.1750 + inTransaction = 1; 1.1751 + } 1.1752 + if (!tableExists(sqlDB,table)) { 1.1753 + *newInit = 1; 1.1754 + if (flags != SDB_CREATE) { 1.1755 + error = sdb_mapSQLError(type, SQLITE_CANTOPEN); 1.1756 + goto loser; 1.1757 + } 1.1758 + initStr = sqlite3_mprintf(""); 1.1759 + for (i=0; initStr && i < known_attributes_size; i++) { 1.1760 + newStr = sqlite3_mprintf("%s, a%x",initStr, known_attributes[i]); 1.1761 + sqlite3_free(initStr); 1.1762 + initStr = newStr; 1.1763 + } 1.1764 + if (initStr == NULL) { 1.1765 + error = CKR_HOST_MEMORY; 1.1766 + goto loser; 1.1767 + } 1.1768 + 1.1769 + newStr = sqlite3_mprintf(INIT_CMD, table, initStr); 1.1770 + sqlite3_free(initStr); 1.1771 + if (newStr == NULL) { 1.1772 + error = CKR_HOST_MEMORY; 1.1773 + goto loser; 1.1774 + } 1.1775 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.1776 + sqlite3_free(newStr); 1.1777 + if (sqlerr != SQLITE_OK) { 1.1778 + error = sdb_mapSQLError(type, sqlerr); 1.1779 + goto loser; 1.1780 + } 1.1781 + 1.1782 + newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, table); 1.1783 + if (newStr == NULL) { 1.1784 + error = CKR_HOST_MEMORY; 1.1785 + goto loser; 1.1786 + } 1.1787 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.1788 + sqlite3_free(newStr); 1.1789 + if (sqlerr != SQLITE_OK) { 1.1790 + error = sdb_mapSQLError(type, sqlerr); 1.1791 + goto loser; 1.1792 + } 1.1793 + 1.1794 + newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, table); 1.1795 + if (newStr == NULL) { 1.1796 + error = CKR_HOST_MEMORY; 1.1797 + goto loser; 1.1798 + } 1.1799 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.1800 + sqlite3_free(newStr); 1.1801 + if (sqlerr != SQLITE_OK) { 1.1802 + error = sdb_mapSQLError(type, sqlerr); 1.1803 + goto loser; 1.1804 + } 1.1805 + 1.1806 + newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, table); 1.1807 + if (newStr == NULL) { 1.1808 + error = CKR_HOST_MEMORY; 1.1809 + goto loser; 1.1810 + } 1.1811 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.1812 + sqlite3_free(newStr); 1.1813 + if (sqlerr != SQLITE_OK) { 1.1814 + error = sdb_mapSQLError(type, sqlerr); 1.1815 + goto loser; 1.1816 + } 1.1817 + 1.1818 + newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, table); 1.1819 + if (newStr == NULL) { 1.1820 + error = CKR_HOST_MEMORY; 1.1821 + goto loser; 1.1822 + } 1.1823 + sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); 1.1824 + sqlite3_free(newStr); 1.1825 + if (sqlerr != SQLITE_OK) { 1.1826 + error = sdb_mapSQLError(type, sqlerr); 1.1827 + goto loser; 1.1828 + } 1.1829 + } 1.1830 + /* 1.1831 + * detect the case where we have created the database, but have 1.1832 + * not yet updated it. 1.1833 + * 1.1834 + * We only check the Key database because only the key database has 1.1835 + * a metaData table. The metaData table is created when a password 1.1836 + * is set, or in the case of update, when a password is supplied. 1.1837 + * If no key database exists, then the update would have happened immediately 1.1838 + * on noticing that the cert database didn't exist (see newInit set above). 1.1839 + */ 1.1840 + if (type == SDB_KEY && !tableExists(sqlDB, "metaData")) { 1.1841 + *newInit = 1; 1.1842 + } 1.1843 + 1.1844 + /* access to network filesystems are significantly slower than local ones 1.1845 + * for database operations. In those cases we need to create a cached copy 1.1846 + * of the database in a temporary location on the local disk. SQLITE 1.1847 + * already provides a way to create a temporary table and initialize it, 1.1848 + * so we use it for the cache (see sdb_buildCache for how it's done).*/ 1.1849 + 1.1850 + /* 1.1851 + * we decide whether or not to use the cache based on the following input. 1.1852 + * 1.1853 + * NSS_SDB_USE_CACHE environment variable is non-existant or set to 1.1854 + * anything other than "no" or "yes" ("auto", for instance). 1.1855 + * This is the normal case. NSS will measure the performance of access 1.1856 + * to the temp database versus the access to the users passed in 1.1857 + * database location. If the temp database location is "significantly" 1.1858 + * faster we will use the cache. 1.1859 + * 1.1860 + * NSS_SDB_USE_CACHE environment variable is set to "no": cache will not 1.1861 + * be used. 1.1862 + * 1.1863 + * NSS_SDB_USE_CACHE environment variable is set to "yes": cache will 1.1864 + * always be used. 1.1865 + * 1.1866 + * It is expected that most applications would use the "auto" selection, 1.1867 + * the environment variable is primarily to simplify testing, and to 1.1868 + * correct potential corner cases where */ 1.1869 + 1.1870 + env = PR_GetEnv("NSS_SDB_USE_CACHE"); 1.1871 + 1.1872 + if (env && PORT_Strcasecmp(env,"no") == 0) { 1.1873 + enableCache = PR_FALSE; 1.1874 + } else if (env && PORT_Strcasecmp(env,"yes") == 0) { 1.1875 + enableCache = PR_TRUE; 1.1876 + } else { 1.1877 + char *tempDir = NULL; 1.1878 + PRUint32 tempOps = 0; 1.1879 + /* 1.1880 + * Use PR_Access to determine how expensive it 1.1881 + * is to check for the existance of a local file compared to the same 1.1882 + * check in the temp directory. If the temp directory is faster, cache 1.1883 + * the database there. */ 1.1884 + tempDir = sdb_getTempDir(sqlDB); 1.1885 + if (tempDir) { 1.1886 + tempOps = sdb_measureAccess(tempDir); 1.1887 + PORT_Free(tempDir); 1.1888 + 1.1889 + /* There is a cost to continually copying the database. 1.1890 + * Account for that cost with the arbitrary factor of 10 */ 1.1891 + enableCache = (PRBool)(tempOps > accessOps * 10); 1.1892 + } 1.1893 + } 1.1894 + 1.1895 + if (enableCache) { 1.1896 + /* try to set the temp store to memory.*/ 1.1897 + sqlite3_exec(sqlDB, "PRAGMA temp_store=MEMORY", NULL, 0, NULL); 1.1898 + /* Failure to set the temp store to memory is not fatal, 1.1899 + * ignore the error */ 1.1900 + 1.1901 + cacheTable = sqlite3_mprintf("%sCache",table); 1.1902 + if (cacheTable == NULL) { 1.1903 + error = CKR_HOST_MEMORY; 1.1904 + goto loser; 1.1905 + } 1.1906 + /* build the cache table */ 1.1907 + error = sdb_buildCache(sqlDB, type, cacheTable, table); 1.1908 + if (error != CKR_OK) { 1.1909 + goto loser; 1.1910 + } 1.1911 + /* initialize the last cache build time */ 1.1912 + now = PR_IntervalNow(); 1.1913 + } 1.1914 + 1.1915 + sdb = (SDB *) malloc(sizeof(SDB)); 1.1916 + sdb_p = (SDBPrivate *) malloc(sizeof(SDBPrivate)); 1.1917 + 1.1918 + /* invariant fields */ 1.1919 + sdb_p->sqlDBName = PORT_Strdup(dbname); 1.1920 + sdb_p->type = type; 1.1921 + sdb_p->table = table; 1.1922 + sdb_p->cacheTable = cacheTable; 1.1923 + sdb_p->lastUpdateTime = now; 1.1924 + /* set the cache delay time. This is how long we will wait before we 1.1925 + * decide the existing cache is stale. Currently set to 10 sec */ 1.1926 + sdb_p->updateInterval = PR_SecondsToInterval(10); 1.1927 + sdb_p->dbMon = PR_NewMonitor(); 1.1928 + /* these fields are protected by the lock */ 1.1929 + sdb_p->sqlXactDB = NULL; 1.1930 + sdb_p->sqlXactThread = NULL; 1.1931 + sdb->private = sdb_p; 1.1932 + sdb->version = 0; 1.1933 + sdb->sdb_flags = flags | SDB_HAS_META; 1.1934 + sdb->app_private = NULL; 1.1935 + sdb->sdb_FindObjectsInit = sdb_FindObjectsInit; 1.1936 + sdb->sdb_FindObjects = sdb_FindObjects; 1.1937 + sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal; 1.1938 + sdb->sdb_GetAttributeValue = sdb_GetAttributeValue; 1.1939 + sdb->sdb_SetAttributeValue = sdb_SetAttributeValue; 1.1940 + sdb->sdb_CreateObject = sdb_CreateObject; 1.1941 + sdb->sdb_DestroyObject = sdb_DestroyObject; 1.1942 + sdb->sdb_GetMetaData = sdb_GetMetaData; 1.1943 + sdb->sdb_PutMetaData = sdb_PutMetaData; 1.1944 + sdb->sdb_Begin = sdb_Begin; 1.1945 + sdb->sdb_Commit = sdb_Commit; 1.1946 + sdb->sdb_Abort = sdb_Abort; 1.1947 + sdb->sdb_Reset = sdb_Reset; 1.1948 + sdb->sdb_Close = sdb_Close; 1.1949 + sdb->sdb_SetForkState = sdb_SetForkState; 1.1950 + 1.1951 + if (inTransaction) { 1.1952 + sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL); 1.1953 + if (sqlerr != SQLITE_OK) { 1.1954 + error = sdb_mapSQLError(sdb_p->type, sqlerr); 1.1955 + goto loser; 1.1956 + } 1.1957 + inTransaction = 0; 1.1958 + } 1.1959 + 1.1960 + sdb_p->sqlReadDB = sqlDB; 1.1961 + 1.1962 + *pSdb = sdb; 1.1963 + UNLOCK_SQLITE(); 1.1964 + return CKR_OK; 1.1965 + 1.1966 +loser: 1.1967 + /* lots of stuff to do */ 1.1968 + if (inTransaction) { 1.1969 + sqlite3_exec(sqlDB, ROLLBACK_CMD, NULL, 0, NULL); 1.1970 + } 1.1971 + if (sdb) { 1.1972 + free(sdb); 1.1973 + } 1.1974 + if (sdb_p) { 1.1975 + free(sdb_p); 1.1976 + } 1.1977 + if (sqlDB) { 1.1978 + sqlite3_close(sqlDB); 1.1979 + } 1.1980 + UNLOCK_SQLITE(); 1.1981 + return error; 1.1982 + 1.1983 +} 1.1984 + 1.1985 + 1.1986 +/* sdbopen */ 1.1987 +CK_RV 1.1988 +s_open(const char *directory, const char *certPrefix, const char *keyPrefix, 1.1989 + int cert_version, int key_version, int flags, 1.1990 + SDB **certdb, SDB **keydb, int *newInit) 1.1991 +{ 1.1992 + char *cert = sdb_BuildFileName(directory, certPrefix, 1.1993 + "cert", cert_version); 1.1994 + char *key = sdb_BuildFileName(directory, keyPrefix, 1.1995 + "key", key_version); 1.1996 + CK_RV error = CKR_OK; 1.1997 + int inUpdate; 1.1998 + PRUint32 accessOps; 1.1999 + 1.2000 + if (certdb) 1.2001 + *certdb = NULL; 1.2002 + if (keydb) 1.2003 + *keydb = NULL; 1.2004 + *newInit = 0; 1.2005 + 1.2006 +#ifdef SQLITE_UNSAFE_THREADS 1.2007 + if (sqlite_lock == NULL) { 1.2008 + sqlite_lock = PR_NewLock(); 1.2009 + if (sqlite_lock == NULL) { 1.2010 + error = CKR_HOST_MEMORY; 1.2011 + goto loser; 1.2012 + } 1.2013 + } 1.2014 +#endif 1.2015 + 1.2016 + /* how long does it take to test for a non-existant file in our working 1.2017 + * directory? Allows us to test if we may be on a network file system */ 1.2018 + accessOps = 1; 1.2019 + { 1.2020 + char *env; 1.2021 + env = PR_GetEnv("NSS_SDB_USE_CACHE"); 1.2022 + /* If the environment variable is set to yes or no, sdb_init() will 1.2023 + * ignore the value of accessOps, and we can skip the measuring.*/ 1.2024 + if (!env || ((PORT_Strcasecmp(env, "no") != 0) && 1.2025 + (PORT_Strcasecmp(env, "yes") != 0))){ 1.2026 + accessOps = sdb_measureAccess(directory); 1.2027 + } 1.2028 + } 1.2029 + 1.2030 + /* 1.2031 + * open the cert data base 1.2032 + */ 1.2033 + if (certdb) { 1.2034 + /* initialize Certificate database */ 1.2035 + error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate, 1.2036 + newInit, flags, accessOps, certdb); 1.2037 + if (error != CKR_OK) { 1.2038 + goto loser; 1.2039 + } 1.2040 + } 1.2041 + 1.2042 + /* 1.2043 + * open the key data base: 1.2044 + * NOTE:if we want to implement a single database, we open 1.2045 + * the same database file as the certificate here. 1.2046 + * 1.2047 + * cert an key db's have different tables, so they will not 1.2048 + * conflict. 1.2049 + */ 1.2050 + if (keydb) { 1.2051 + /* initialize the Key database */ 1.2052 + error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate, 1.2053 + newInit, flags, accessOps, keydb); 1.2054 + if (error != CKR_OK) { 1.2055 + goto loser; 1.2056 + } 1.2057 + } 1.2058 + 1.2059 + 1.2060 +loser: 1.2061 + if (cert) { 1.2062 + sqlite3_free(cert); 1.2063 + } 1.2064 + if (key) { 1.2065 + sqlite3_free(key); 1.2066 + } 1.2067 + 1.2068 + if (error != CKR_OK) { 1.2069 + /* currently redundant, but could be necessary if more code is added 1.2070 + * just before loser */ 1.2071 + if (keydb && *keydb) { 1.2072 + sdb_Close(*keydb); 1.2073 + } 1.2074 + if (certdb && *certdb) { 1.2075 + sdb_Close(*certdb); 1.2076 + } 1.2077 + } 1.2078 + 1.2079 + return error; 1.2080 +} 1.2081 + 1.2082 +CK_RV 1.2083 +s_shutdown() 1.2084 +{ 1.2085 +#ifdef SQLITE_UNSAFE_THREADS 1.2086 + if (sqlite_lock) { 1.2087 + PR_DestroyLock(sqlite_lock); 1.2088 + sqlite_lock = NULL; 1.2089 + } 1.2090 +#endif 1.2091 + return CKR_OK; 1.2092 +}