Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / softoken / sdb.c
blob2642a991d4bca29d52a9dae925a77a64ea342882
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is Red Hat, Inc.
16 * The Initial Developer of the Original Code is
17 * Red Hat, Inc.
18 * Portions created by the Initial Developer are Copyright (C) 2005
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Robert Relyea (rrelyea@redhat.com)
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 * This file implements PKCS 11 on top of our existing security modules
40 * For more information about PKCS 11 See PKCS 11 Token Inteface Standard.
41 * This implementation has two slots:
42 * slot 1 is our generic crypto support. It does not require login.
43 * It supports Public Key ops, and all they bulk ciphers and hashes.
44 * It can also support Private Key ops for imported Private keys. It does
45 * not have any token storage.
46 * slot 2 is our private key support. It requires a login before use. It
47 * can store Private Keys and Certs as token objects. Currently only private
48 * keys and their associated Certificates are saved on the token.
50 * In this implementation, session objects are only visible to the session
51 * that created or generated them.
54 #include "sdb.h"
55 #include "pkcs11t.h"
56 #include "seccomon.h"
57 #include <sqlite3.h>
58 #include "prthread.h"
59 #include "prio.h"
60 #include "stdio.h"
62 #include "prlock.h"
64 #ifdef SQLITE_UNSAFE_THREADS
66 * SQLite can be compiled to be thread safe or not.
67 * turn on SQLITE_UNSAFE_THREADS if the OS does not support
68 * a thread safe version of sqlite.
70 static PRLock *sqlite_lock = NULL;
72 #define LOCK_SQLITE() PR_Lock(sqlite_lock);
73 #define UNLOCK_SQLITE() PR_Unlock(sqlite_lock);
74 #else
75 #define LOCK_SQLITE()
76 #define UNLOCK_SQLITE()
77 #endif
79 typedef enum {
80 SDB_CERT = 1,
81 SDB_KEY = 2
82 } sdbDataType;
84 struct SDBPrivateStr {
85 char *sqlDBName; /* invarient, path to this database */
86 sqlite3 *sqlXactDB; /* protected by lock, current transaction db*/
87 PRThread *sqlXactThread; /* protected by lock,
88 * current transaiction thred*/
89 sdbDataType type; /* invariant, database type */
90 char *table; /* invariant, SQL table which contains the db */
91 PRLock *lock; /* invariant, lock to protect sqlXact* fields*/
94 typedef struct SDBPrivateStr SDBPrivate;
97 * known attributes
99 static const CK_ATTRIBUTE_TYPE known_attributes[] = {
100 CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION,
101 CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER,
102 CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED,
103 CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL,
104 CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY,
105 CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE,
106 CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER,
107 CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE,
108 CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
109 CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT,
110 CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS,
111 CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE,
112 CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE,
113 CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS,
114 CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
115 CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE,
116 CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT,
117 CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS,
118 CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
119 CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
120 CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
121 CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NETSCAPE_URL, CKA_NETSCAPE_EMAIL,
122 CKA_NETSCAPE_SMIME_INFO, CKA_NETSCAPE_SMIME_TIMESTAMP,
123 CKA_NETSCAPE_PKCS8_SALT, CKA_NETSCAPE_PASSWORD_CHECK, CKA_NETSCAPE_EXPIRES,
124 CKA_NETSCAPE_KRL, CKA_NETSCAPE_PQG_COUNTER, CKA_NETSCAPE_PQG_SEED,
125 CKA_NETSCAPE_PQG_H, CKA_NETSCAPE_PQG_SEED_BITS, CKA_NETSCAPE_MODULE_SPEC,
126 CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION,
127 CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT,
128 CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN,
129 CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING,
130 CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM,
131 CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
132 CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
133 CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS
136 static int known_attributes_size= sizeof(known_attributes)/
137 sizeof(known_attributes[0]);
139 /* Magic for an explicit NULL. NOTE: ideally this should be
140 * out of band data. Since it's not completely out of band, pick
141 * a value that has no meaning to any existing PKCS #11 attributes.
142 * This value is 1) not a valid string (imbedded '\0'). 2) not a U_LONG
143 * or a normal key (too short). 3) not a bool (too long). 4) not an RSA
144 * public exponent (too many bits).
146 const unsigned char SQLITE_EXPLICIT_NULL[] = { 0xa5, 0x0, 0x5a };
147 #define SQLITE_EXPLICIT_NULL_LEN 3
150 * determine when we've completed our tasks
152 #define MAX_RETRIES 10
153 static int
154 sdb_done(int err, int *count)
156 /* allow as many rows as the database wants to give */
157 if (err == SQLITE_ROW) {
158 *count = 0;
159 return 0;
161 if (err != SQLITE_BUSY) {
162 return 1;
164 /* err == SQLITE_BUSY, Dont' retry forever in this case */
165 if (++(*count) >= MAX_RETRIES) {
166 return 1;
168 return 0;
172 * Map SQL_LITE errors to PKCS #11 errors as best we can.
174 static int
175 sdb_mapSQLError(sdbDataType type, int sqlerr)
177 switch (sqlerr) {
178 /* good matches */
179 case SQLITE_OK:
180 case SQLITE_DONE:
181 return CKR_OK;
182 case SQLITE_NOMEM:
183 return CKR_HOST_MEMORY;
184 case SQLITE_READONLY:
185 return CKR_TOKEN_WRITE_PROTECTED;
186 /* close matches */
187 case SQLITE_AUTH:
188 case SQLITE_PERM:
189 /*return CKR_USER_NOT_LOGGED_IN; */
190 case SQLITE_CANTOPEN:
191 case SQLITE_NOTFOUND:
192 /* NSS distiguishes between failure to open the cert and the key db */
193 return type == SDB_CERT ?
194 CKR_NETSCAPE_CERTDB_FAILED : CKR_NETSCAPE_KEYDB_FAILED;
195 case SQLITE_IOERR:
196 return CKR_DEVICE_ERROR;
197 default:
198 break;
200 return CKR_GENERAL_ERROR;
204 * sqlite3 cannot share handles across threads, in general.
205 * PKCS #11 modules can be called thread, so we need to constantly open and
206 * close the sqlite database.
208 * The one exception is transactions. When we are in a transaction, we must
209 * use the same database pointer for that entire transation. In this case
210 * we save the transaction database and use it for all accesses on the
211 * transaction thread. Other threads still get their own database.
213 * There can only be once active transaction on the database at a time.
215 static CK_RV
216 sdb_openDBLocal(SDBPrivate *sdb_p, sqlite3 **sqlDB)
218 #ifdef SQLITE_THREAD_SHARE_DB
219 *sqlDB = sdb_p->sqlXactDB;
220 return CKR_OK;
221 #else
223 int sqlerr = SQLITE_OK;
224 CK_RV error = CKR_OK;
226 char *dbname = sdb_p->sqlDBName;
227 sdbDataType type = sdb_p->type;
229 *sqlDB = NULL;
231 PR_Lock(sdb_p->lock);
233 /* We're in a transaction, use the transaction DB */
234 if ((sdb_p->sqlXactDB) && (sdb_p->sqlXactThread == PR_GetCurrentThread())) {
235 *sqlDB =sdb_p->sqlXactDB;
236 /* only one thread can get here, safe to unlock */
237 PR_Unlock(sdb_p->lock);
238 return CKR_OK;
241 /* we're and independent operation, get our own db handle */
242 PR_Unlock(sdb_p->lock);
244 sqlerr = sqlite3_open(dbname, sqlDB);
245 if (sqlerr != SQLITE_OK) {
246 error = sdb_mapSQLError(type, sqlerr);
247 goto loser;
250 sqlerr = sqlite3_busy_timeout(*sqlDB, 1000);
251 if (sqlerr != CKR_OK) {
252 error = sdb_mapSQLError(type, sqlerr);
253 goto loser;
255 return error;
257 loser:
258 if (*sqlDB) {
259 sqlite3_close(*sqlDB);
260 *sqlDB = NULL;
262 return error;
263 #endif
266 /* down with the local database, free it if we allocated it, otherwise
267 * free unlock our use the the transaction database */
268 static CK_RV
269 sdb_closeDBLocal(SDBPrivate *sdb_p, sqlite3 *sqlDB)
271 #ifndef SQLITE_THREAD_SHARE_DB
272 if (sdb_p->sqlXactDB != sqlDB) {
273 sqlite3_close(sqlDB);
275 #endif
276 return CKR_OK;
279 struct SDBFindStr {
280 sqlite3 *sqlDB;
281 sqlite3_stmt *findstmt;
285 #define FIND_OBJECTS_CMD "SELECT ALL * FROM %s WHERE %s;"
286 #define FIND_OBJECTS_ALL_CMD "SELECT ALL * FROM %s;"
287 CK_RV
288 sdb_FindObjectsInit(SDB *sdb, const CK_ATTRIBUTE *template, CK_ULONG count,
289 SDBFind **find)
291 SDBPrivate *sdb_p = sdb->private;
292 sqlite3 *sqlDB = NULL;
293 char *newStr, *findStr = NULL;
294 sqlite3_stmt *findstmt = NULL;
295 char *join="";
296 int sqlerr = SQLITE_OK;
297 CK_RV error = CKR_OK;
298 int i;
300 LOCK_SQLITE()
301 *find = NULL;
302 error = sdb_openDBLocal(sdb_p, &sqlDB);
303 if (error != CKR_OK) {
304 goto loser;
307 findStr = sqlite3_mprintf("");
308 for (i=0; findStr && i < count; i++) {
309 newStr = sqlite3_mprintf("%s%sa%x=$DATA%d", findStr, join,
310 template[i].type, i);
311 join=" AND ";
312 sqlite3_free(findStr);
313 findStr = newStr;
316 if (findStr == NULL) {
317 error = CKR_HOST_MEMORY;
318 goto loser;
321 if (count == 0) {
322 newStr = sqlite3_mprintf(FIND_OBJECTS_ALL_CMD, sdb_p->table);
323 } else {
324 newStr = sqlite3_mprintf(FIND_OBJECTS_CMD, sdb_p->table, findStr);
326 sqlite3_free(findStr);
327 if (newStr == NULL) {
328 error = CKR_HOST_MEMORY;
329 goto loser;
331 sqlerr = sqlite3_prepare(sqlDB, newStr, -1, &findstmt, NULL);
332 sqlite3_free(newStr);
333 for (i=0; sqlerr == SQLITE_OK && i < count; i++) {
334 sqlerr = sqlite3_bind_blob(findstmt, i+1, template[i].pValue,
335 template[i].ulValueLen, SQLITE_TRANSIENT);
337 if (sqlerr == SQLITE_OK) {
338 *find = PORT_New(SDBFind);
339 if (*find == NULL) {
340 error = CKR_HOST_MEMORY;
341 goto loser;
343 (*find)->findstmt = findstmt;
344 (*find)->sqlDB = sqlDB;
345 UNLOCK_SQLITE()
346 return CKR_OK;
348 error = sdb_mapSQLError(sdb_p->type, sqlerr);
350 loser:
351 if (findstmt) {
352 sqlite3_finalize(findstmt);
354 if (sqlDB) {
355 sdb_closeDBLocal(sdb_p, sqlDB) ;
357 UNLOCK_SQLITE()
358 return error;
362 CK_RV
363 sdb_FindObjects(SDB *sdb, SDBFind *sdbFind, CK_OBJECT_HANDLE *object,
364 CK_ULONG arraySize, CK_ULONG *count)
366 SDBPrivate *sdb_p = sdb->private;
367 sqlite3_stmt *stmt = sdbFind->findstmt;
368 int sqlerr = SQLITE_OK;
369 int retry = 0;
371 *count = 0;
373 if (arraySize == 0) {
374 return CKR_OK;
376 LOCK_SQLITE()
378 do {
379 sqlerr = sqlite3_step(stmt);
380 if (sqlerr == SQLITE_BUSY) {
381 PR_Sleep(5);
383 if (sqlerr == SQLITE_ROW) {
384 /* only care about the id */
385 *object++= sqlite3_column_int(stmt, 0);
386 arraySize--;
387 (*count)++;
389 } while (!sdb_done(sqlerr,&retry) && (arraySize > 0));
391 /* we only have some of the objects, there is probably more,
392 * set the sqlerr to an OK value so we return CKR_OK */
393 if (sqlerr == SQLITE_ROW && arraySize == 0) {
394 sqlerr = SQLITE_DONE;
396 UNLOCK_SQLITE()
398 return sdb_mapSQLError(sdb_p->type, sqlerr);
401 CK_RV
402 sdb_FindObjectsFinal(SDB *sdb, SDBFind *sdbFind)
404 SDBPrivate *sdb_p = sdb->private;
405 sqlite3_stmt *stmt = sdbFind->findstmt;
406 sqlite3 *sqlDB = sdbFind->sqlDB;
407 int sqlerr = SQLITE_OK;
409 LOCK_SQLITE()
410 if (stmt) {
411 sqlite3_reset(stmt);
412 sqlerr = sqlite3_finalize(stmt);
414 if (sqlDB) {
415 sdb_closeDBLocal(sdb_p, sqlDB) ;
417 PORT_Free(sdbFind);
419 UNLOCK_SQLITE()
420 return sdb_mapSQLError(sdb_p->type, sqlerr);
423 #define GET_ATTRIBUTE_CMD "SELECT ALL %s FROM %s WHERE id=$ID;"
424 CK_RV
425 sdb_GetAttributeValueNoLock(SDB *sdb, CK_OBJECT_HANDLE object_id,
426 CK_ATTRIBUTE *template, CK_ULONG count)
428 SDBPrivate *sdb_p = sdb->private;
429 sqlite3 *sqlDB = NULL;
430 sqlite3_stmt *stmt = NULL;
431 char *getStr = NULL;
432 char *newStr = NULL;
433 int sqlerr = SQLITE_OK;
434 CK_RV error = CKR_OK;
435 int found = 0;
436 int retry = 0;
437 int i;
439 getStr = sqlite3_mprintf("");
440 for (i=0; getStr && i < count; i++) {
441 if (i==0) {
442 newStr = sqlite3_mprintf("a%x", template[i].type);
443 } else {
444 newStr = sqlite3_mprintf("%s, a%x", getStr, template[i].type);
446 sqlite3_free(getStr);
447 getStr = newStr;
450 if (getStr == NULL) {
451 error = CKR_HOST_MEMORY;
452 goto loser;
455 newStr = sqlite3_mprintf(GET_ATTRIBUTE_CMD, getStr, sdb_p->table);
456 sqlite3_free(getStr);
457 getStr = NULL;
458 if (newStr == NULL) {
459 error = CKR_HOST_MEMORY;
460 goto loser;
462 /* open a new db if necessary */
463 error = sdb_openDBLocal(sdb_p,&sqlDB);
464 if (error != CKR_OK) {
465 goto loser;
467 sqlerr = sqlite3_prepare(sqlDB, newStr, -1, &stmt, NULL);
468 if (sqlerr != SQLITE_OK) { goto loser; }
469 sqlerr = sqlite3_bind_int(stmt, 1, object_id);
470 if (sqlerr != SQLITE_OK) { goto loser; }
471 do {
472 sqlerr = sqlite3_step(stmt);
473 if (sqlerr == SQLITE_BUSY) {
474 PR_Sleep(5);
476 if (sqlerr == SQLITE_ROW) {
477 for (i=0; i < count; i++) {
478 int column = i;
479 int blobSize;
480 const char *blobData;
482 blobSize = sqlite3_column_bytes(stmt, column);
483 blobData = sqlite3_column_blob(stmt, column);
484 if (blobData == NULL) {
485 template[i].ulValueLen = -1;
486 error = CKR_ATTRIBUTE_TYPE_INVALID;
487 continue;
489 /* If the blob equals our explicit NULL value, then the
490 * attribute is a NULL. */
491 if ((blobSize == SQLITE_EXPLICIT_NULL_LEN) &&
492 (PORT_Memcmp(blobData, SQLITE_EXPLICIT_NULL,
493 SQLITE_EXPLICIT_NULL_LEN) == 0)) {
494 blobSize = 0;
496 if (template[i].pValue) {
497 if (template[i].ulValueLen < blobSize) {
498 template[i].ulValueLen = -1;
499 error = CKR_BUFFER_TOO_SMALL;
500 continue;
502 PORT_Memcpy(template[i].pValue, blobData, blobSize);
504 template[i].ulValueLen = blobSize;
506 found = 1;
508 } while (!sdb_done(sqlerr,&retry));
510 loser:
511 /* fix up the error if necessary */
512 if (error == CKR_OK) {
513 error = sdb_mapSQLError(sdb_p->type, sqlerr);
514 if (!found && error == CKR_OK) {
515 error = CKR_OBJECT_HANDLE_INVALID;
518 if (newStr) {
519 sqlite3_free(newStr);
522 if (stmt) {
523 sqlite3_reset(stmt);
524 sqlite3_finalize(stmt);
527 /* if we had to open a new database, free it now */
528 if (sqlDB) {
529 sdb_closeDBLocal(sdb_p, sqlDB) ;
531 return error;
534 CK_RV
535 sdb_GetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id,
536 CK_ATTRIBUTE *template, CK_ULONG count)
538 CK_RV crv;
540 if (count == 0) {
541 return CKR_OK;
544 LOCK_SQLITE()
545 crv = sdb_GetAttributeValueNoLock(sdb, object_id, template, count);
546 UNLOCK_SQLITE()
547 return crv;
550 #define SET_ATTRIBUTE_CMD "UPDATE %s SET %s WHERE id=$ID;"
551 CK_RV
552 sdb_SetAttributeValue(SDB *sdb, CK_OBJECT_HANDLE object_id,
553 const CK_ATTRIBUTE *template, CK_ULONG count)
555 SDBPrivate *sdb_p = sdb->private;
556 sqlite3 *sqlDB = NULL;
557 sqlite3_stmt *stmt = NULL;
558 char *setStr = NULL;
559 char *newStr = NULL;
560 int sqlerr = SQLITE_OK;
561 int retry = 0;
562 CK_RV error = CKR_OK;
563 int i;
565 if (sdb->sdb_flags == SDB_RDONLY) {
566 return CKR_TOKEN_WRITE_PROTECTED;
569 if (count == 0) {
570 return CKR_OK;
573 LOCK_SQLITE()
574 setStr = sqlite3_mprintf("");
575 for (i=0; setStr && i < count; i++) {
576 if (i==0) {
577 sqlite3_free(setStr);
578 setStr = sqlite3_mprintf("a%x=$VALUE%d",
579 template[i].type, i);
580 continue;
582 newStr = sqlite3_mprintf("%s,a%x=$VALUE%d", setStr,
583 template[i].type, i);
584 sqlite3_free(setStr);
585 setStr = newStr;
587 newStr = NULL;
589 if (setStr == NULL) {
590 return CKR_HOST_MEMORY;
592 newStr = sqlite3_mprintf(SET_ATTRIBUTE_CMD, sdb_p->table, setStr);
593 sqlite3_free(setStr);
594 if (newStr == NULL) {
595 UNLOCK_SQLITE()
596 return CKR_HOST_MEMORY;
598 error = sdb_openDBLocal(sdb_p, &sqlDB);
599 if (error != CKR_OK) {
600 goto loser;
602 sqlerr = sqlite3_prepare(sqlDB, newStr, -1, &stmt, NULL);
603 if (sqlerr != SQLITE_OK) goto loser;
604 for (i=0; i < count; i++) {
605 if (template[i].ulValueLen != 0) {
606 sqlerr = sqlite3_bind_blob(stmt, i+1, template[i].pValue,
607 template[i].ulValueLen, SQLITE_STATIC);
608 } else {
609 sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL,
610 SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC);
612 if (sqlerr != SQLITE_OK) goto loser;
614 sqlerr = sqlite3_bind_int(stmt, i+1, object_id);
615 if (sqlerr != SQLITE_OK) goto loser;
617 do {
618 sqlerr = sqlite3_step(stmt);
619 if (sqlerr == SQLITE_BUSY) {
620 PR_Sleep(5);
622 } while (!sdb_done(sqlerr,&retry));
624 loser:
625 if (newStr) {
626 sqlite3_free(newStr);
628 if (error == CKR_OK) {
629 error = sdb_mapSQLError(sdb_p->type, sqlerr);
632 if (stmt) {
633 sqlite3_reset(stmt);
634 sqlite3_finalize(stmt);
637 if (sqlDB) {
638 sdb_closeDBLocal(sdb_p, sqlDB) ;
641 UNLOCK_SQLITE()
642 return error;
646 * check to see if a candidate object handle already exists.
648 static PRBool
649 sdb_objectExists(SDB *sdb, CK_OBJECT_HANDLE candidate)
651 CK_RV crv;
652 CK_ATTRIBUTE template = { CKA_LABEL, NULL, 0 };
654 crv = sdb_GetAttributeValueNoLock(sdb,candidate,&template, 1);
655 if (crv == CKR_OBJECT_HANDLE_INVALID) {
656 return PR_FALSE;
658 return PR_TRUE;
662 * if we're here, we are in a transaction, so it's safe
663 * to examine the current state of the database
665 static CK_OBJECT_HANDLE
666 sdb_getObjectId(SDB *sdb)
668 CK_OBJECT_HANDLE candidate;
669 static CK_OBJECT_HANDLE next_obj = CK_INVALID_HANDLE;
670 int count;
672 * get an initial object handle to use
674 if (next_obj == CK_INVALID_HANDLE) {
675 PRTime time;
676 time = PR_Now();
678 next_obj = (CK_OBJECT_HANDLE)(time & 0x3fffffffL);
680 candidate = next_obj++;
681 /* detect that we've looped through all the handles... */
682 for (count = 0; count < 0x40000000; count++, candidate = next_obj++) {
683 /* mask off excess bits */
684 candidate &= 0x3fffffff;
685 /* if we hit zero, go to the next entry */
686 if (candidate == CK_INVALID_HANDLE) {
687 continue;
689 /* make sure we aren't already using */
690 if (!sdb_objectExists(sdb, candidate)) {
691 /* this one is free */
692 return candidate;
696 /* no handle is free, fail */
697 return CK_INVALID_HANDLE;
700 #define CREATE_CMD "INSERT INTO %s (id%s) VALUES($ID%s);"
701 CK_RV
702 sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id,
703 const CK_ATTRIBUTE *template, CK_ULONG count)
705 SDBPrivate *sdb_p = sdb->private;
706 sqlite3 *sqlDB = NULL;
707 sqlite3_stmt *stmt = NULL;
708 char *columnStr = NULL;
709 char *valueStr = NULL;
710 char *newStr = NULL;
711 int sqlerr = SQLITE_OK;
712 CK_RV error = CKR_OK;
713 CK_OBJECT_HANDLE this_object;
714 int retry = 0;
715 int i;
717 if (sdb->sdb_flags == SDB_RDONLY) {
718 return CKR_TOKEN_WRITE_PROTECTED;
721 LOCK_SQLITE()
722 if ((*object_id != CK_INVALID_HANDLE) &&
723 !sdb_objectExists(sdb, *object_id)) {
724 this_object = *object_id;
725 } else {
726 this_object = sdb_getObjectId(sdb);
728 if (this_object == CK_INVALID_HANDLE) {
729 UNLOCK_SQLITE();
730 return CKR_HOST_MEMORY;
732 columnStr = sqlite3_mprintf("");
733 valueStr = sqlite3_mprintf("");
734 *object_id = this_object;
735 for (i=0; columnStr && valueStr && i < count; i++) {
736 newStr = sqlite3_mprintf("%s,a%x", columnStr, template[i].type);
737 sqlite3_free(columnStr);
738 columnStr = newStr;
739 newStr = sqlite3_mprintf("%s,$VALUE%d", valueStr, i);
740 sqlite3_free(valueStr);
741 valueStr = newStr;
743 newStr = NULL;
744 if ((columnStr == NULL) || (valueStr == NULL)) {
745 if (columnStr) {
746 sqlite3_free(columnStr);
748 if (valueStr) {
749 sqlite3_free(valueStr);
751 UNLOCK_SQLITE()
752 return CKR_HOST_MEMORY;
754 newStr = sqlite3_mprintf(CREATE_CMD, sdb_p->table, columnStr, valueStr);
755 sqlite3_free(columnStr);
756 sqlite3_free(valueStr);
757 error = sdb_openDBLocal(sdb_p, &sqlDB);
758 if (error != CKR_OK) {
759 goto loser;
761 sqlerr = sqlite3_prepare(sqlDB, newStr, -1, &stmt, NULL);
762 if (sqlerr != SQLITE_OK) goto loser;
763 sqlerr = sqlite3_bind_int(stmt, 1, *object_id);
764 if (sqlerr != SQLITE_OK) goto loser;
765 for (i=0; i < count; i++) {
766 if (template[i].ulValueLen) {
767 sqlerr = sqlite3_bind_blob(stmt, i+2, template[i].pValue,
768 template[i].ulValueLen, SQLITE_STATIC);
769 } else {
770 sqlerr = sqlite3_bind_blob(stmt, i+2, SQLITE_EXPLICIT_NULL,
771 SQLITE_EXPLICIT_NULL_LEN, SQLITE_STATIC);
773 if (sqlerr != SQLITE_OK) goto loser;
776 do {
777 sqlerr = sqlite3_step(stmt);
778 if (sqlerr == SQLITE_BUSY) {
779 PR_Sleep(5);
781 } while (!sdb_done(sqlerr,&retry));
783 loser:
784 if (newStr) {
785 sqlite3_free(newStr);
787 if (error == CKR_OK) {
788 error = sdb_mapSQLError(sdb_p->type, sqlerr);
791 if (stmt) {
792 sqlite3_reset(stmt);
793 sqlite3_finalize(stmt);
796 if (sqlDB) {
797 sdb_closeDBLocal(sdb_p, sqlDB) ;
799 UNLOCK_SQLITE()
801 return error;
804 #define DESTROY_CMD "DELETE FROM %s WHERE (id=$ID);"
805 CK_RV
806 sdb_DestroyObject(SDB *sdb, CK_OBJECT_HANDLE object_id)
808 SDBPrivate *sdb_p = sdb->private;
809 sqlite3 *sqlDB = NULL;
810 sqlite3_stmt *stmt = NULL;
811 char *newStr = NULL;
812 int sqlerr = SQLITE_OK;
813 CK_RV error = CKR_OK;
814 int retry = 0;
816 if (sdb->sdb_flags == SDB_RDONLY) {
817 return CKR_TOKEN_WRITE_PROTECTED;
820 LOCK_SQLITE()
821 error = sdb_openDBLocal(sdb_p, &sqlDB);
822 if (error != CKR_OK) {
823 goto loser;
825 newStr = sqlite3_mprintf(DESTROY_CMD, sdb_p->table);
826 if (newStr == NULL) {
827 error = CKR_HOST_MEMORY;
828 goto loser;
830 sqlerr =sqlite3_prepare(sqlDB, newStr, -1, &stmt, NULL);
831 sqlite3_free(newStr);
832 if (sqlerr != SQLITE_OK) goto loser;
833 sqlerr =sqlite3_bind_int(stmt, 1, object_id);
834 if (sqlerr != SQLITE_OK) goto loser;
836 do {
837 sqlerr = sqlite3_step(stmt);
838 if (sqlerr == SQLITE_BUSY) {
839 PR_Sleep(5);
841 } while (!sdb_done(sqlerr,&retry));
843 loser:
844 if (error == CKR_OK) {
845 error = sdb_mapSQLError(sdb_p->type, sqlerr);
848 if (stmt) {
849 sqlite3_reset(stmt);
850 sqlite3_finalize(stmt);
853 if (sqlDB) {
854 sdb_closeDBLocal(sdb_p, sqlDB) ;
857 UNLOCK_SQLITE()
858 return error;
861 #define BEGIN_CMD "BEGIN IMMEDIATE TRANSACTION;"
863 * start a transaction.
865 * We need to open a new database, then store that new database into
866 * the private data structure. We open the database first, then use locks
867 * to protect storing the data to prevent deadlocks.
869 CK_RV
870 sdb_Begin(SDB *sdb)
872 SDBPrivate *sdb_p = sdb->private;
873 sqlite3 *sqlDB = NULL;
874 sqlite3_stmt *stmt = NULL;
875 int sqlerr = SQLITE_OK;
876 CK_RV error = CKR_OK;
877 int retry = 0;
880 if (sdb->sdb_flags == SDB_RDONLY) {
881 return CKR_TOKEN_WRITE_PROTECTED;
885 LOCK_SQLITE()
886 #ifdef SQLITE_THREAD_SHARE_DB
887 sqlDB = sdb_p->sqlXactDB;
888 #else
889 /* get a new version that we will use for the entire transaction */
890 sqlerr = sqlite3_open(sdb_p->sqlDBName, &sqlDB);
891 if (sqlerr != SQLITE_OK) {
892 goto loser;
894 #endif
896 sqlerr = sqlite3_busy_timeout(sqlDB, 1000);
897 if (sqlerr != CKR_OK) {
898 goto loser;
901 sqlerr =sqlite3_prepare(sqlDB, BEGIN_CMD, -1, &stmt, NULL);
903 do {
904 sqlerr = sqlite3_step(stmt);
905 if (sqlerr == SQLITE_BUSY) {
906 PR_Sleep(5);
908 } while (!sdb_done(sqlerr,&retry));
910 if (stmt) {
911 sqlite3_reset(stmt);
912 sqlite3_finalize(stmt);
915 loser:
916 error = sdb_mapSQLError(sdb_p->type, sqlerr);
918 #ifndef SQLITE_THREAD_SHARE_DB
919 /* we are starting a new transaction,
920 * and if we succeeded, then save this database for the rest of
921 * our transaction */
922 if (error == CKR_OK) {
923 /* we hold a 'BEGIN TRANSACTION' and a sdb_p->lock. At this point
924 * sdb_p->sqlXactDB MUST be null */
925 PR_Lock(sdb_p->lock);
926 PORT_Assert(sdb_p->sqlXactDB == NULL);
927 sdb_p->sqlXactDB = sqlDB;
928 sdb_p->sqlXactThread = PR_GetCurrentThread();
929 PR_Unlock(sdb_p->lock);
930 } else {
931 /* we failed to start our transaction,
932 * free any databases we openned. */
933 if (sqlDB) {
934 sqlite3_close(sqlDB);
937 #endif
939 UNLOCK_SQLITE()
940 return error;
944 * Complete a transaction. Basically undo everything we did in begin.
945 * There are 2 flavors Abort and Commit. Basically the only differerence between
946 * these 2 are what the database will show. (no change in to former, change in
947 * the latter).
949 static CK_RV
950 sdb_complete(SDB *sdb, const char *cmd)
952 SDBPrivate *sdb_p = sdb->private;
953 sqlite3 *sqlDB = NULL;
954 sqlite3_stmt *stmt = NULL;
955 int sqlerr = SQLITE_OK;
956 CK_RV error = CKR_OK;
957 int retry = 0;
960 if (sdb->sdb_flags == SDB_RDONLY) {
961 return CKR_TOKEN_WRITE_PROTECTED;
965 #ifndef SQLITE_THREAD_SHARE_DB
966 /* We must have a transation database, or we shouldn't have arrived here */
967 PR_Lock(sdb_p->lock);
968 PORT_Assert(sdb_p->sqlXactDB);
969 if (sdb_p->sqlXactDB == NULL) {
970 PR_Unlock(sdb_p->lock);
971 return CKR_GENERAL_ERROR; /* shouldn't happen */
973 PORT_Assert( sdb_p->sqlXactThread == PR_GetCurrentThread());
974 if ( sdb_p->sqlXactThread != PR_GetCurrentThread()) {
975 PR_Unlock(sdb_p->lock);
976 return CKR_GENERAL_ERROR; /* shouldn't happen */
978 sqlDB = sdb_p->sqlXactDB;
979 sdb_p->sqlXactDB = NULL; /* no one else can get to this DB,
980 * safe to unlock */
981 sdb_p->sqlXactThread = NULL;
982 PR_Unlock(sdb_p->lock);
983 #else
984 sqlDB = sdb_p->sqlXactDB;
985 #endif
987 sqlerr =sqlite3_prepare(sqlDB, cmd, -1, &stmt, NULL);
989 do {
990 sqlerr = sqlite3_step(stmt);
991 if (sqlerr == SQLITE_BUSY) {
992 PR_Sleep(5);
994 } while (!sdb_done(sqlerr,&retry));
996 /* Pending BEGIN TRANSACTIONS Can move forward at this point. */
998 if (stmt) {
999 sqlite3_reset(stmt);
1000 sqlite3_finalize(stmt);
1003 error = sdb_mapSQLError(sdb_p->type, sqlerr);
1005 #ifndef SQLITE_THREAD_SHARE_DB
1006 /* We just finished a transaction.
1007 * Free the database, and remove it from the list */
1008 sqlite3_close(sqlDB);
1009 #endif
1011 return error;
1014 #define COMMIT_CMD "COMMIT TRANSACTION;"
1015 CK_RV
1016 sdb_Commit(SDB *sdb)
1018 CK_RV crv;
1019 LOCK_SQLITE()
1020 crv = sdb_complete(sdb,COMMIT_CMD);
1021 UNLOCK_SQLITE()
1022 return crv;
1025 #define ROLLBACK_CMD "ROLLBACK TRANSACTION;"
1026 CK_RV
1027 sdb_Abort(SDB *sdb)
1029 CK_RV crv;
1030 LOCK_SQLITE()
1031 crv = sdb_complete(sdb,ROLLBACK_CMD);
1032 UNLOCK_SQLITE()
1033 return crv;
1036 #define GET_PW_CMD "SELECT ALL * FROM password WHERE id='password';"
1037 CK_RV
1038 sdb_GetPWEntry(SDB *sdb, SDBPasswordEntry *entry)
1040 SDBPrivate *sdb_p = sdb->private;
1041 sqlite3 *sqlDB = sdb_p->sqlXactDB;
1042 sqlite3_stmt *stmt = NULL;
1043 int sqlerr = SQLITE_OK;
1044 CK_RV error = CKR_OK;
1045 int found = 0;
1046 int retry = 0;
1048 /* only Key databases have password entries */
1049 if (sdb_p->type != SDB_KEY) {
1050 return CKR_OBJECT_HANDLE_INVALID;
1053 LOCK_SQLITE()
1054 error = sdb_openDBLocal(sdb_p, &sqlDB);
1055 if (error != CKR_OK) {
1056 goto loser;
1059 sqlerr = sqlite3_prepare(sqlDB, GET_PW_CMD, -1, &stmt, NULL);
1060 do {
1061 sqlerr = sqlite3_step(stmt);
1062 if (sqlerr == SQLITE_BUSY) {
1063 PR_Sleep(5);
1065 if (sqlerr == SQLITE_ROW) {
1066 const char *blobData;
1067 entry->salt.data = entry->data;
1068 entry->salt.len = sqlite3_column_bytes(stmt, 1);
1069 if (entry->salt.len > sizeof(entry->data)) {
1070 error = CKR_BUFFER_TOO_SMALL;
1071 continue;
1073 blobData = sqlite3_column_blob(stmt, 1);
1074 PORT_Memcpy(entry->salt.data,blobData, entry->salt.len);
1075 entry->value.data = &entry->data[entry->salt.len];
1076 entry->value.len = sqlite3_column_bytes(stmt, 2);
1077 if ((entry->value.len+entry->salt.len) > sizeof(entry->data)) {
1078 error = CKR_BUFFER_TOO_SMALL;
1079 continue;
1081 blobData = sqlite3_column_blob(stmt, 2);
1082 PORT_Memcpy(entry->value.data,blobData, entry->value.len);
1083 found = 1;
1085 } while (!sdb_done(sqlerr,&retry));
1087 loser:
1088 /* fix up the error if necessary */
1089 if (error == CKR_OK) {
1090 error = sdb_mapSQLError(sdb_p->type, sqlerr);
1091 if (!found && error == CKR_OK) {
1092 error = CKR_OBJECT_HANDLE_INVALID;
1096 if (stmt) {
1097 sqlite3_reset(stmt);
1098 sqlite3_finalize(stmt);
1101 if (sqlDB) {
1102 sdb_closeDBLocal(sdb_p, sqlDB) ;
1104 UNLOCK_SQLITE()
1106 return error;
1109 static int tableExists(sqlite3 *sqlDB, const char *tableName);
1110 #define PW_CREATE_TABLE_CMD \
1111 "CREATE TABLE password (id PRIMARY KEY UNIQUE ON CONFLICT REPLACE, salt, value);"
1112 #define PW_CREATE_CMD \
1113 "INSERT INTO password (id,salt,value) VALUES('password',$SALT,$VALUE);"
1114 CK_RV
1115 sdb_PutPWEntry(SDB *sdb, SDBPasswordEntry *entry)
1117 SDBPrivate *sdb_p = sdb->private;
1118 sqlite3 *sqlDB = sdb_p->sqlXactDB;
1119 sqlite3_stmt *stmt = NULL;
1120 int sqlerr = SQLITE_OK;
1121 CK_RV error = CKR_OK;
1122 int retry = 0;
1124 /* only Key databases have password entries */
1125 if (sdb_p->type != SDB_KEY) {
1126 return CKR_OBJECT_HANDLE_INVALID;
1129 LOCK_SQLITE()
1130 error = sdb_openDBLocal(sdb_p, &sqlDB);
1131 if (error != CKR_OK) {
1132 goto loser;
1135 if (!tableExists(sqlDB, "password")) {
1136 sqlerr = sqlite3_exec(sqlDB, PW_CREATE_TABLE_CMD, NULL, 0, NULL);
1137 if (sqlerr != SQLITE_OK) goto loser;
1139 sqlerr = sqlite3_prepare(sqlDB, PW_CREATE_CMD, -1, &stmt, NULL);
1140 if (sqlerr != SQLITE_OK) goto loser;
1141 sqlerr = sqlite3_bind_blob(stmt, 1, entry->salt.data,
1142 entry->salt.len, SQLITE_STATIC);
1143 if (sqlerr != SQLITE_OK) goto loser;
1144 sqlerr = sqlite3_bind_blob(stmt, 2, entry->value.data,
1145 entry->value.len, SQLITE_STATIC);
1146 if (sqlerr != SQLITE_OK) goto loser;
1148 do {
1149 sqlerr = sqlite3_step(stmt);
1150 if (sqlerr == SQLITE_BUSY) {
1151 PR_Sleep(5);
1153 } while (!sdb_done(sqlerr,&retry));
1155 loser:
1156 /* fix up the error if necessary */
1157 if (error == CKR_OK) {
1158 error = sdb_mapSQLError(sdb_p->type, sqlerr);
1161 if (stmt) {
1162 sqlite3_reset(stmt);
1163 sqlite3_finalize(stmt);
1166 if (sqlDB) {
1167 sdb_closeDBLocal(sdb_p, sqlDB) ;
1169 UNLOCK_SQLITE()
1171 return error;
1174 #define RESET_CMD "DROP TABLE IF EXISTS %s;"
1175 CK_RV
1176 sdb_Reset(SDB *sdb)
1178 SDBPrivate *sdb_p = sdb->private;
1179 sqlite3 *sqlDB = NULL;
1180 char *newStr;
1181 int sqlerr = SQLITE_OK;
1182 CK_RV error = CKR_OK;
1184 /* only Key databases can be reset */
1185 if (sdb_p->type != SDB_KEY) {
1186 return CKR_OBJECT_HANDLE_INVALID;
1189 LOCK_SQLITE()
1190 error = sdb_openDBLocal(sdb_p, &sqlDB);
1191 if (error != CKR_OK) {
1192 goto loser;
1195 /* delete the key table */
1196 newStr = sqlite3_mprintf(RESET_CMD, sdb_p->table);
1197 if (newStr == NULL) {
1198 error = CKR_HOST_MEMORY;
1199 goto loser;
1201 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
1202 sqlite3_free(newStr);
1204 if (sqlerr != SQLITE_OK) goto loser;
1206 /* delete the password entry table */
1207 sqlerr = sqlite3_exec(sqlDB, "DROP TABLE IF EXISTS password;",
1208 NULL, 0, NULL);
1210 loser:
1211 /* fix up the error if necessary */
1212 if (error == CKR_OK) {
1213 error = sdb_mapSQLError(sdb_p->type, sqlerr);
1216 if (sqlDB) {
1217 sdb_closeDBLocal(sdb_p, sqlDB) ;
1220 UNLOCK_SQLITE()
1221 return error;
1225 CK_RV
1226 sdb_Close(SDB *sdb)
1228 SDBPrivate *sdb_p = sdb->private;
1229 int sqlerr = SQLITE_OK;
1230 sdbDataType type = sdb_p->type;
1232 /* sqlerr = sqlite3_close(sqlDB); */
1233 PORT_Free(sdb_p->sqlDBName);
1234 free(sdb_p);
1235 free(sdb);
1236 return sdb_mapSQLError(type, sqlerr);
1241 * functions to support open
1244 #define CHECK_TABLE_CMD "SELECT ALL * FROM %s LIMIT 0;"
1245 /* return 1 if sqlDB contains table 'tableName */
1246 static int tableExists(sqlite3 *sqlDB, const char *tableName)
1248 char * cmd = sqlite3_mprintf(CHECK_TABLE_CMD, tableName);
1249 int sqlerr = SQLITE_OK;
1251 if (cmd == NULL) {
1252 return 0;
1255 sqlerr = sqlite3_exec(sqlDB, cmd, NULL, 0, 0);
1256 sqlite3_free(cmd);
1258 return (sqlerr == SQLITE_OK) ? 1 : 0;
1262 * initialize a single database
1264 #define INIT_CMD \
1265 "CREATE TABLE %s (id PRIMARY KEY UNIQUE ON CONFLICT ABORT%s)"
1266 #define ALTER_CMD \
1267 "ALTER TABLE %s ADD COLUMN a%x"
1270 CK_RV
1271 sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate,
1272 int *newInit, int flags, SDB **pSdb)
1274 int i;
1275 char *initStr = NULL;
1276 char *newStr;
1277 int inTransaction = 0;
1278 SDB *sdb = NULL;
1279 SDBPrivate *sdb_p = NULL;
1280 sqlite3 *sqlDB = NULL;
1281 int sqlerr = SQLITE_OK;
1282 CK_RV error = CKR_OK;
1284 *pSdb = NULL;
1285 *inUpdate = 0;
1287 /* sqlite3 doesn't have a flag to specify that we want to
1288 * open the database read only. If the db doesn't exist,
1289 * sqlite3 will always create it.
1291 LOCK_SQLITE();
1292 if ((flags == SDB_RDONLY) && PR_Access(dbname, PR_ACCESS_EXISTS)) {
1293 error = sdb_mapSQLError(type, SQLITE_CANTOPEN);
1294 goto loser;
1296 sqlerr = sqlite3_open(dbname, &sqlDB);
1297 if (sqlerr != SQLITE_OK) {
1298 error = sdb_mapSQLError(type, sqlerr);
1299 goto loser;
1302 sqlerr = sqlite3_busy_timeout(sqlDB, 1000);
1303 if (sqlerr != CKR_OK) {
1304 error = sdb_mapSQLError(type, sqlerr);
1305 goto loser;
1308 if (flags != SDB_RDONLY) {
1309 sqlerr = sqlite3_exec(sqlDB, BEGIN_CMD, NULL, 0, NULL);
1310 if (sqlerr != SQLITE_OK) {
1311 error = sdb_mapSQLError(type, sqlerr);
1312 goto loser;
1314 inTransaction = 1;
1316 if (!tableExists(sqlDB,table)) {
1317 *newInit = 1;
1318 if (flags != SDB_CREATE) {
1319 error = sdb_mapSQLError(type, SQLITE_CANTOPEN);
1320 goto loser;
1322 initStr = sqlite3_mprintf("");
1323 for (i=0; initStr && i < known_attributes_size; i++) {
1324 newStr = sqlite3_mprintf("%s, a%x",initStr, known_attributes[i]);
1325 sqlite3_free(initStr);
1326 initStr = newStr;
1328 if (initStr == NULL) {
1329 error = CKR_HOST_MEMORY;
1330 goto loser;
1332 newStr = sqlite3_mprintf(INIT_CMD, table, initStr);
1333 sqlite3_free(initStr);
1334 sqlerr = sqlite3_exec(sqlDB, newStr, NULL, 0, NULL);
1335 sqlite3_free(newStr);
1336 if (sqlerr != SQLITE_OK) {
1337 error = sdb_mapSQLError(type, sqlerr);
1338 goto loser;
1340 } else {
1341 /* if the nssInit table exists, then someone else is initing the
1342 * nss database. We don't want to complete the open until the init
1343 * is completed. */
1344 if (tableExists(sqlDB,"nssInUpdate")) {
1345 *inUpdate = 1;
1348 sdb = (SDB *) malloc(sizeof(SDB));
1349 sdb_p = (SDBPrivate *) malloc(sizeof(SDBPrivate));
1350 /* invariant fields */
1351 sdb_p->sqlDBName = PORT_Strdup(dbname);
1352 sdb_p->type = type;
1353 sdb_p->table = table;
1354 sdb_p->lock = PR_NewLock();
1355 /* these fields are protected by the lock */
1356 sdb_p->sqlXactDB = NULL;
1357 sdb_p->sqlXactThread = NULL;
1358 sdb->private = sdb_p;
1359 sdb->sdb_type = SDB_SQL;
1360 sdb->sdb_flags = flags;
1361 sdb->sdb_FindObjectsInit = sdb_FindObjectsInit;
1362 sdb->sdb_FindObjects = sdb_FindObjects;
1363 sdb->sdb_FindObjectsFinal = sdb_FindObjectsFinal;
1364 sdb->sdb_GetAttributeValue = sdb_GetAttributeValue;
1365 sdb->sdb_SetAttributeValue = sdb_SetAttributeValue;
1366 sdb->sdb_CreateObject = sdb_CreateObject;
1367 sdb->sdb_DestroyObject = sdb_DestroyObject;
1368 sdb->sdb_GetPWEntry = sdb_GetPWEntry;
1369 sdb->sdb_PutPWEntry = sdb_PutPWEntry;
1370 sdb->sdb_Begin = sdb_Begin;
1371 sdb->sdb_Commit = sdb_Commit;
1372 sdb->sdb_Abort = sdb_Abort;
1373 sdb->sdb_Close = sdb_Close;
1375 if (inTransaction) {
1376 sqlerr = sqlite3_exec(sqlDB, COMMIT_CMD, NULL, 0, NULL);
1377 if (sqlerr != SQLITE_OK) {
1378 error = sdb_mapSQLError(sdb_p->type, sqlerr);
1379 goto loser;
1381 inTransaction = 0;
1383 if (*inUpdate) {
1384 while (tableExists(sqlDB,"nssInit")) {
1385 PR_Sleep(5);
1388 #ifdef SQLITE_THREAD_SHARE_DB
1389 sdb_p->sqlXactDB = sqlDB;
1390 #else
1391 /* sqlite3 cannot share sqlDB references across threads, open the
1392 * db only when we need to read or update it (sigh) */
1393 sqlite3_close(sqlDB);
1394 #endif
1396 *pSdb = sdb;
1397 UNLOCK_SQLITE();
1398 return CKR_OK;
1400 loser:
1401 /* lots of stuff to do */
1402 if (inTransaction) {
1403 sqlite3_exec(sqlDB, ROLLBACK_CMD, NULL, 0, NULL);
1405 if (sdb) {
1406 free(sdb);
1408 if (sdb_p) {
1409 free(sdb_p);
1411 if (sqlDB) {
1412 sqlite3_close(sqlDB);
1414 UNLOCK_SQLITE();
1415 return error;
1419 static char *sdb_BuildFileName(const char * directory,
1420 const char *prefix, const char *type,
1421 int version, int flags)
1423 char *dbname = NULL;
1424 /* build the full dbname */
1425 dbname = sqlite3_mprintf("%s/%s%s%d.db",directory, prefix, type, version);
1426 return dbname;
1429 /* sdbopen */
1430 CK_RV
1431 s_open(const char *directory, const char *certPrefix, const char *keyPrefix,
1432 int cert_version, int key_version, int flags,
1433 SDB **certdb, SDB **keydb, int *newInit)
1435 char *cert = sdb_BuildFileName(directory, certPrefix,
1436 "cert", cert_version, flags);
1437 char *key = sdb_BuildFileName(directory, keyPrefix,
1438 "key", key_version, flags);
1439 CK_RV error = CKR_OK;
1440 int inUpdate;
1442 *certdb = NULL;
1443 *keydb = NULL;
1444 *newInit = 0;
1446 #ifdef SQLITE_UNSAFE_THREADS
1447 if (sqlite_lock == NULL) {
1448 sqlite_lock = PR_NewLock();
1449 if (sqlite_lock == NULL) {
1450 error = CKR_HOST_MEMORY;
1451 goto loser;
1454 #endif
1457 * open the cert data base
1459 if (certdb) {
1460 /* initialize Certificate database */
1461 error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate,
1462 newInit, flags, certdb);
1463 if (error != CKR_OK) {
1464 goto loser;
1469 * open the key data base:
1470 * NOTE:is we want to implement a single database, we open
1471 * the same database file as the certificate here.
1473 * cert an key db's have different tables, so they will not
1474 * conflict.
1476 if (keydb) {
1477 /* initialize the Key database */
1478 error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate,
1479 newInit, flags, keydb);
1480 if (error != CKR_OK) {
1481 goto loser;
1486 loser:
1487 if (cert) {
1488 sqlite3_free(cert);
1490 if (key) {
1491 sqlite3_free(key);
1494 if (error != CKR_OK) {
1495 /* currently redundant, but could be necessary if more code is added
1496 * just before loser */
1497 if (keydb && *keydb) {
1498 sdb_Close(*keydb);
1500 if (certdb && *certdb) {
1501 sdb_Close(*certdb);
1505 return error;
1508 CK_RV
1509 s_shutdown()
1511 #ifdef SQLITE_UNSAFE_THREADS
1512 if (sqlite_lock) {
1513 PR_DestroyLock(sqlite_lock);
1514 sqlite_lock = NULL;
1516 #endif
1517 return CKR_OK;