diff options
Diffstat (limited to 'pkcs11.c')
-rw-r--r-- | pkcs11.c | 200 |
1 files changed, 199 insertions, 1 deletions
@@ -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; |