Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/softoken/sdb.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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] = getenv("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 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 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 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 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 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 static const char ALTER_CMD[] = | |
1695 "ALTER TABLE %s ADD COLUMN a%x"; | |
1696 | |
1697 CK_RV | |
1698 sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, | |
1699 int *newInit, int flags, PRUint32 accessOps, SDB **pSdb) | |
1700 { | |
1701 int i; | |
1702 char *initStr = NULL; | |
1703 char *newStr; | |
1704 int inTransaction = 0; | |
1705 SDB *sdb = NULL; | |
1706 SDBPrivate *sdb_p = NULL; | |
1707 sqlite3 *sqlDB = NULL; | |
1708 int sqlerr = SQLITE_OK; | |
1709 CK_RV error = CKR_OK; | |
1710 char *cacheTable = NULL; | |
1711 PRIntervalTime now = 0; | |
1712 char *env; | |
1713 PRBool enableCache = PR_FALSE; | |
1714 PRBool create; | |
1715 | |
1716 *pSdb = NULL; | |
1717 *inUpdate = 0; | |
1718 | |
1719 /* sqlite3 doesn't have a flag to specify that we want to | |
1720 * open the database read only. If the db doesn't exist, | |
1721 * sqlite3 will always create it. | |
1722 */ | |
1723 LOCK_SQLITE(); | |
1724 create = (PR_Access(dbname, PR_ACCESS_EXISTS) != PR_SUCCESS); | |
1725 if ((flags == SDB_RDONLY) && create) { | |
1726 error = sdb_mapSQLError(type, SQLITE_CANTOPEN); | |
1727 goto loser; | |
1728 } | |
1729 sqlerr = sdb_openDB(dbname, &sqlDB, flags); | |
1730 if (sqlerr != SQLITE_OK) { | |
1731 error = sdb_mapSQLError(type, sqlerr); | |
1732 goto loser; | |
1733 } | |
1734 /* sql created the file, but it doesn't set appropriate modes for | |
1735 * a database */ | |
1736 if (create) { | |
1737 /* NO NSPR call for this? :( */ | |
1738 chmod (dbname, 0600); | |
1739 } | |
1740 | |
1741 if (flags != SDB_RDONLY) { | |
1742 sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL); | |
1743 if (sqlerr != SQLITE_OK) { | |
1744 error = sdb_mapSQLError(type, sqlerr); | |
1745 goto loser; | |
1746 } | |
1747 inTransaction = 1; | |
1748 } | |
1749 if (!tableExists(sqlDB,table)) { | |
1750 *newInit = 1; | |
1751 if (flags != SDB_CREATE) { | |
1752 error = sdb_mapSQLError(type, SQLITE_CANTOPEN); | |
1753 goto loser; | |
1754 } | |
1755 initStr = sqlite3_mprintf(""); | |
1756 for (i=0; initStr && i < known_attributes_size; i++) { | |
1757 newStr = sqlite3_mprintf("%s, a%x",initStr, known_attributes[i]); | |
1758 sqlite3_free(initStr); | |
1759 initStr = newStr; | |
1760 } | |
1761 if (initStr == NULL) { | |
1762 error = CKR_HOST_MEMORY; | |
1763 goto loser; | |
1764 } | |
1765 | |
1766 newStr = sqlite3_mprintf(INIT_CMD, table, initStr); | |
1767 sqlite3_free(initStr); | |
1768 if (newStr == NULL) { | |
1769 error = CKR_HOST_MEMORY; | |
1770 goto loser; | |
1771 } | |
1772 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
1773 sqlite3_free(newStr); | |
1774 if (sqlerr != SQLITE_OK) { | |
1775 error = sdb_mapSQLError(type, sqlerr); | |
1776 goto loser; | |
1777 } | |
1778 | |
1779 newStr = sqlite3_mprintf(CREATE_ISSUER_INDEX_CMD, table); | |
1780 if (newStr == NULL) { | |
1781 error = CKR_HOST_MEMORY; | |
1782 goto loser; | |
1783 } | |
1784 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
1785 sqlite3_free(newStr); | |
1786 if (sqlerr != SQLITE_OK) { | |
1787 error = sdb_mapSQLError(type, sqlerr); | |
1788 goto loser; | |
1789 } | |
1790 | |
1791 newStr = sqlite3_mprintf(CREATE_SUBJECT_INDEX_CMD, table); | |
1792 if (newStr == NULL) { | |
1793 error = CKR_HOST_MEMORY; | |
1794 goto loser; | |
1795 } | |
1796 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
1797 sqlite3_free(newStr); | |
1798 if (sqlerr != SQLITE_OK) { | |
1799 error = sdb_mapSQLError(type, sqlerr); | |
1800 goto loser; | |
1801 } | |
1802 | |
1803 newStr = sqlite3_mprintf(CREATE_LABEL_INDEX_CMD, table); | |
1804 if (newStr == NULL) { | |
1805 error = CKR_HOST_MEMORY; | |
1806 goto loser; | |
1807 } | |
1808 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
1809 sqlite3_free(newStr); | |
1810 if (sqlerr != SQLITE_OK) { | |
1811 error = sdb_mapSQLError(type, sqlerr); | |
1812 goto loser; | |
1813 } | |
1814 | |
1815 newStr = sqlite3_mprintf(CREATE_ID_INDEX_CMD, table); | |
1816 if (newStr == NULL) { | |
1817 error = CKR_HOST_MEMORY; | |
1818 goto loser; | |
1819 } | |
1820 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL); | |
1821 sqlite3_free(newStr); | |
1822 if (sqlerr != SQLITE_OK) { | |
1823 error = sdb_mapSQLError(type, sqlerr); | |
1824 goto loser; | |
1825 } | |
1826 } | |
1827 /* | |
1828 * detect the case where we have created the database, but have | |
1829 * not yet updated it. | |
1830 * | |
1831 * We only check the Key database because only the key database has | |
1832 * a metaData table. The metaData table is created when a password | |
1833 * is set, or in the case of update, when a password is supplied. | |
1834 * If no key database exists, then the update would have happened immediately | |
1835 * on noticing that the cert database didn't exist (see newInit set above). | |
1836 */ | |
1837 if (type == SDB_KEY && !tableExists(sqlDB, "metaData")) { | |
1838 *newInit = 1; | |
1839 } | |
1840 | |
1841 /* access to network filesystems are significantly slower than local ones | |
1842 * for database operations. In those cases we need to create a cached copy | |
1843 * of the database in a temporary location on the local disk. SQLITE | |
1844 * already provides a way to create a temporary table and initialize it, | |
1845 * so we use it for the cache (see sdb_buildCache for how it's done).*/ | |
1846 | |
1847 /* | |
1848 * we decide whether or not to use the cache based on the following input. | |
1849 * | |
1850 * NSS_SDB_USE_CACHE environment variable is non-existant or set to | |
1851 * anything other than "no" or "yes" ("auto", for instance). | |
1852 * This is the normal case. NSS will measure the performance of access | |
1853 * to the temp database versus the access to the users passed in | |
1854 * database location. If the temp database location is "significantly" | |
1855 * faster we will use the cache. | |
1856 * | |
1857 * NSS_SDB_USE_CACHE environment variable is set to "no": cache will not | |
1858 * be used. | |
1859 * | |
1860 * NSS_SDB_USE_CACHE environment variable is set to "yes": cache will | |
1861 * always be used. | |
1862 * | |
1863 * It is expected that most applications would use the "auto" selection, | |
1864 * the environment variable is primarily to simplify testing, and to | |
1865 * correct potential corner cases where */ | |
1866 | |
1867 env = PR_GetEnv("NSS_SDB_USE_CACHE"); | |
1868 | |
1869 if (env && PORT_Strcasecmp(env,"no") == 0) { | |
1870 enableCache = PR_FALSE; | |
1871 } else if (env && PORT_Strcasecmp(env,"yes") == 0) { | |
1872 enableCache = PR_TRUE; | |
1873 } else { | |
1874 char *tempDir = NULL; | |
1875 PRUint32 tempOps = 0; | |
1876 /* | |
1877 * Use PR_Access to determine how expensive it | |
1878 * is to check for the existance of a local file compared to the same | |
1879 * check in the temp directory. If the temp directory is faster, cache | |
1880 * the database there. */ | |
1881 tempDir = sdb_getTempDir(sqlDB); | |
1882 if (tempDir) { | |
1883 tempOps = sdb_measureAccess(tempDir); | |
1884 PORT_Free(tempDir); | |
1885 | |
1886 /* There is a cost to continually copying the database. | |
1887 * Account for that cost with the arbitrary factor of 10 */ | |
1888 enableCache = (PRBool)(tempOps > accessOps * 10); | |
1889 } | |
1890 } | |
1891 | |
1892 if (enableCache) { | |
1893 /* try to set the temp store to memory.*/ | |
1894 sqlite3_exec(sqlDB, "PRAGMA temp_store=MEMORY", NULL, 0, NULL); | |
1895 /* Failure to set the temp store to memory is not fatal, | |
1896 * ignore the error */ | |
1897 | |
1898 cacheTable = sqlite3_mprintf("%sCache",table); | |
1899 if (cacheTable == NULL) { | |
1900 error = CKR_HOST_MEMORY; | |
1901 goto loser; | |
1902 } | |
1903 /* build the cache table */ | |
1904 error = sdb_buildCache(sqlDB, type, cacheTable, table); | |
1905 if (error != CKR_OK) { | |
1906 goto loser; | |
1907 } | |
1908 /* initialize the last cache build time */ | |
1909 now = PR_IntervalNow(); | |
1910 } | |
1911 | |
1912 sdb = (SDB *) malloc(sizeof(SDB)); | |
1913 sdb_p = (SDBPrivate *) malloc(sizeof(SDBPrivate)); | |
1914 | |
1915 /* invariant fields */ | |
1916 sdb_p->sqlDBName = PORT_Strdup(dbname); | |
1917 sdb_p->type = type; | |
1918 sdb_p->table = table; | |
1919 sdb_p->cacheTable = cacheTable; | |
1920 sdb_p->lastUpdateTime = now; | |
1921 /* set the cache delay time. This is how long we will wait before we | |
1922 * decide the existing cache is stale. Currently set to 10 sec */ | |
1923 sdb_p->updateInterval = PR_SecondsToInterval(10); | |
1924 sdb_p->dbMon = PR_NewMonitor(); | |
1925 /* these fields are protected by the lock */ | |
1926 sdb_p->sqlXactDB = NULL; | |
1927 sdb_p->sqlXactThread = NULL; | |
1928 sdb->private = sdb_p; | |
1929 sdb->version = 0; | |
1930 sdb->sdb_flags = flags | SDB_HAS_META; | |
1931 sdb->app_private = NULL; | |
1932 sdb->sdb_FindObjectsInit = sdb_FindObjectsInit; | |
1933 sdb->sdb_FindObjects = sdb_FindObjects; | |
1934 sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal; | |
1935 sdb->sdb_GetAttributeValue = sdb_GetAttributeValue; | |
1936 sdb->sdb_SetAttributeValue = sdb_SetAttributeValue; | |
1937 sdb->sdb_CreateObject = sdb_CreateObject; | |
1938 sdb->sdb_DestroyObject = sdb_DestroyObject; | |
1939 sdb->sdb_GetMetaData = sdb_GetMetaData; | |
1940 sdb->sdb_PutMetaData = sdb_PutMetaData; | |
1941 sdb->sdb_Begin = sdb_Begin; | |
1942 sdb->sdb_Commit = sdb_Commit; | |
1943 sdb->sdb_Abort = sdb_Abort; | |
1944 sdb->sdb_Reset = sdb_Reset; | |
1945 sdb->sdb_Close = sdb_Close; | |
1946 sdb->sdb_SetForkState = sdb_SetForkState; | |
1947 | |
1948 if (inTransaction) { | |
1949 sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL); | |
1950 if (sqlerr != SQLITE_OK) { | |
1951 error = sdb_mapSQLError(sdb_p->type, sqlerr); | |
1952 goto loser; | |
1953 } | |
1954 inTransaction = 0; | |
1955 } | |
1956 | |
1957 sdb_p->sqlReadDB = sqlDB; | |
1958 | |
1959 *pSdb = sdb; | |
1960 UNLOCK_SQLITE(); | |
1961 return CKR_OK; | |
1962 | |
1963 loser: | |
1964 /* lots of stuff to do */ | |
1965 if (inTransaction) { | |
1966 sqlite3_exec(sqlDB, ROLLBACK_CMD, NULL, 0, NULL); | |
1967 } | |
1968 if (sdb) { | |
1969 free(sdb); | |
1970 } | |
1971 if (sdb_p) { | |
1972 free(sdb_p); | |
1973 } | |
1974 if (sqlDB) { | |
1975 sqlite3_close(sqlDB); | |
1976 } | |
1977 UNLOCK_SQLITE(); | |
1978 return error; | |
1979 | |
1980 } | |
1981 | |
1982 | |
1983 /* sdbopen */ | |
1984 CK_RV | |
1985 s_open(const char *directory, const char *certPrefix, const char *keyPrefix, | |
1986 int cert_version, int key_version, int flags, | |
1987 SDB **certdb, SDB **keydb, int *newInit) | |
1988 { | |
1989 char *cert = sdb_BuildFileName(directory, certPrefix, | |
1990 "cert", cert_version); | |
1991 char *key = sdb_BuildFileName(directory, keyPrefix, | |
1992 "key", key_version); | |
1993 CK_RV error = CKR_OK; | |
1994 int inUpdate; | |
1995 PRUint32 accessOps; | |
1996 | |
1997 if (certdb) | |
1998 *certdb = NULL; | |
1999 if (keydb) | |
2000 *keydb = NULL; | |
2001 *newInit = 0; | |
2002 | |
2003 #ifdef SQLITE_UNSAFE_THREADS | |
2004 if (sqlite_lock == NULL) { | |
2005 sqlite_lock = PR_NewLock(); | |
2006 if (sqlite_lock == NULL) { | |
2007 error = CKR_HOST_MEMORY; | |
2008 goto loser; | |
2009 } | |
2010 } | |
2011 #endif | |
2012 | |
2013 /* how long does it take to test for a non-existant file in our working | |
2014 * directory? Allows us to test if we may be on a network file system */ | |
2015 accessOps = 1; | |
2016 { | |
2017 char *env; | |
2018 env = PR_GetEnv("NSS_SDB_USE_CACHE"); | |
2019 /* If the environment variable is set to yes or no, sdb_init() will | |
2020 * ignore the value of accessOps, and we can skip the measuring.*/ | |
2021 if (!env || ((PORT_Strcasecmp(env, "no") != 0) && | |
2022 (PORT_Strcasecmp(env, "yes") != 0))){ | |
2023 accessOps = sdb_measureAccess(directory); | |
2024 } | |
2025 } | |
2026 | |
2027 /* | |
2028 * open the cert data base | |
2029 */ | |
2030 if (certdb) { | |
2031 /* initialize Certificate database */ | |
2032 error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate, | |
2033 newInit, flags, accessOps, certdb); | |
2034 if (error != CKR_OK) { | |
2035 goto loser; | |
2036 } | |
2037 } | |
2038 | |
2039 /* | |
2040 * open the key data base: | |
2041 * NOTE:if we want to implement a single database, we open | |
2042 * the same database file as the certificate here. | |
2043 * | |
2044 * cert an key db's have different tables, so they will not | |
2045 * conflict. | |
2046 */ | |
2047 if (keydb) { | |
2048 /* initialize the Key database */ | |
2049 error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate, | |
2050 newInit, flags, accessOps, keydb); | |
2051 if (error != CKR_OK) { | |
2052 goto loser; | |
2053 } | |
2054 } | |
2055 | |
2056 | |
2057 loser: | |
2058 if (cert) { | |
2059 sqlite3_free(cert); | |
2060 } | |
2061 if (key) { | |
2062 sqlite3_free(key); | |
2063 } | |
2064 | |
2065 if (error != CKR_OK) { | |
2066 /* currently redundant, but could be necessary if more code is added | |
2067 * just before loser */ | |
2068 if (keydb && *keydb) { | |
2069 sdb_Close(*keydb); | |
2070 } | |
2071 if (certdb && *certdb) { | |
2072 sdb_Close(*certdb); | |
2073 } | |
2074 } | |
2075 | |
2076 return error; | |
2077 } | |
2078 | |
2079 CK_RV | |
2080 s_shutdown() | |
2081 { | |
2082 #ifdef SQLITE_UNSAFE_THREADS | |
2083 if (sqlite_lock) { | |
2084 PR_DestroyLock(sqlite_lock); | |
2085 sqlite_lock = NULL; | |
2086 } | |
2087 #endif | |
2088 return CKR_OK; | |
2089 } |