aboutsummaryrefslogtreecommitdiff
path: root/pkcs11.c
diff options
context:
space:
mode:
Diffstat (limited to 'pkcs11.c')
-rw-r--r--pkcs11.c200
1 files changed, 199 insertions, 1 deletions
diff --git a/pkcs11.c b/pkcs11.c
index b1aac5f..55b25e4 100644
--- a/pkcs11.c
+++ b/pkcs11.c
@@ -42,6 +42,8 @@
#include <stdarg.h>
#include <assert.h>
+#include <sqlite3.h>
+
#include <hal.h>
/*
@@ -62,7 +64,7 @@
#include "pkcs11.h"
#include "attributes.h"
-#include "sql_common.h"
+#include "p11_common.h"
/*
* This PKCS #11 implementation is hardwired with one slot, the token
@@ -311,6 +313,202 @@ static int _hal_check(const hal_error_t err, const char * const expr, const char
/*
+ * SQL utilities.
+ */
+
+/*
+ * Debugging control.
+ */
+
+#ifndef DEBUG_SQL
+#define DEBUG_SQL 1
+#endif
+
+/*
+ * Default filename for SQL database lives. Can be overriden at
+ * runtime by setting PKCS11_DATABASE environment variable.
+ */
+
+#ifndef SQL_DATABASE
+#define SQL_DATABASE ".cryptech-pkcs11.db"
+#endif
+
+/*
+ * SQL database.
+ */
+
+static sqlite3 *sqldb = NULL;
+
+/*
+ * Error checking for SQLite calls.
+ */
+
+#if DEBUG_SQL
+
+#define sql_whine(_expr_) \
+ (fprintf(stderr, "%s:%u: %s returned %s\n", \
+ __FILE__, __LINE__, #_expr_, sqlite3_errmsg(sqldb)), \
+ sql_breakpoint())
+
+#else /* DEBUG_SQL */
+
+#define sql_whine(_expr_) \
+ ((void) 0)
+
+#endif /* DEBUG_SQL */
+
+#define sql_check(_good_, _expr_) \
+ ((_expr_) == (_good_) ? 1 : (sql_whine(_expr_), 0))
+
+#define sql_check_ok(_expr_) sql_check(SQLITE_OK, _expr_)
+#define sql_check_row(_expr_) sql_check(SQLITE_ROW, _expr_)
+#define sql_check_done(_expr_) sql_check(SQLITE_DONE, _expr_)
+#define sql_whine_step() sql_whine(sqlite3_step())
+
+/*
+ * Hook on which to hang a debugger breakpoint on SQL errors.
+ */
+
+#if DEBUG_SQL
+static void sql_breakpoint(void)
+{
+ fprintf(stderr, "[sql_breakpoint]\n");
+}
+#endif
+
+/*
+ * Execute SQL code that doesn't require a prepared query.
+ */
+
+static int sql_exec(const char *cmd)
+{
+ char *msg = NULL;
+
+ if (sql_check_ok(sqlite3_exec(sqldb, cmd, NULL, NULL, &msg)))
+ return 1;
+
+#if DEBUG_SQL
+ if (msg != NULL)
+ fprintf(stderr, "[%s]\n", msg);
+#endif
+
+ return 0;
+}
+
+/*
+ * Initialize SQL. This includes loading our schema, portions of
+ * which live in the temp (memory) database thus always need to be
+ * created on startup.
+ */
+
+static int sql_init(void)
+{
+ static const char schema[] =
+#include "schema.h"
+ ;
+
+ assert(sqldb == NULL);
+
+ const char * const env = getenv("PKCS11_DATABASE");
+ const char * const home = getenv("HOME");
+ const char * const base = SQL_DATABASE;
+ int ok;
+
+ if (env != NULL) {
+ ok = sql_check_ok(sqlite3_open(env, &sqldb));
+ }
+
+ else if (home == NULL) {
+ ok = sql_check_ok(sqlite3_open(base, &sqldb));
+ }
+
+ else {
+ char fn[strlen(home) + strlen(base) + 2];
+ snprintf(fn, sizeof(fn), "%s/%s", home, base);
+ ok = sql_check_ok(sqlite3_open(fn, &sqldb));
+ }
+
+ return ok && sql_exec(schema);
+}
+
+/*
+ * Shut down SQL.
+ *
+ * Yes, this can return failure, although it's not clear what we're
+ * meant to do about that if the application is going to shut down
+ * regardless of what we do. I guess we could loop retrying a few
+ * times for errors like SQLITE_BUSY, but that's about it.
+ */
+
+static int sql_fini(void)
+{
+ if (!sql_check_ok(sqlite3_close(sqldb)))
+ return 0;
+
+ sqldb = NULL;
+ return 1;
+}
+
+/*
+ * GCC attribute declaration to help catch format string errors,
+ * ignored by other compilers.
+ */
+
+#ifdef __GNUC__
+static int sql_prepare(sqlite3_stmt **q,
+ const char *format, ...)
+ __attribute__ ((format (printf, 2, 3)));
+#endif
+
+/*
+ * Prepare an SQLite3 query, using vsnprintf() to format the query.
+ *
+ * WARNING WARNING WARNING WARNING
+ *
+ * Do not use this formatting mechanism for anything involving
+ * user-supplied data. It's only intended to handle things like
+ * selecting between two parallel table structures or queries using
+ * manifest constants that are only available in C header files.
+ */
+
+static int sql_prepare(sqlite3_stmt **q, const char *format, ...)
+{
+ char buffer[2048];
+ va_list ap;
+ size_t n;
+
+ va_start(ap, format);
+ n = vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+
+ if (n >= sizeof(buffer))
+ return SQLITE_TOOBIG;
+
+ return sqlite3_prepare_v2(sqldb, buffer, -1, q, NULL);
+}
+
+/*
+ * This idiom occurs frequently, bundle it so we have the option of
+ * doing it along with the normal conditional control flow that SQL
+ * queries seem to follow.
+ */
+
+static int sql_finalize_and_clear(sqlite3_stmt **q)
+{
+ assert(q != NULL);
+
+ int err = sqlite3_finalize(*q);
+
+ if (err != SQLITE_OK)
+ return err;
+
+ *q = NULL;
+ return SQLITE_OK;
+}
+
+
+
+/*
* Thread mutex utilities. We need to handle three separate cases:
*
* 1) User doesn't care about mutexes;