aboutsummaryrefslogtreecommitdiff
path: root/sql_common.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql_common.h')
-rw-r--r--sql_common.h255
1 files changed, 255 insertions, 0 deletions
diff --git a/sql_common.h b/sql_common.h
new file mode 100644
index 0000000..8f1844b
--- /dev/null
+++ b/sql_common.h
@@ -0,0 +1,255 @@
+/*
+ * sql_common.h
+ * ------------
+ *
+ * Common definitions and SQL support code for Cryptech PKCS #11 engine.
+ *
+ * We could split the functions out of this into a separate .c file,
+ * but there's no real point in doing so, and it's simpler to keep it
+ * all in one file, the build process is complex enough already.
+ *
+ * Author: Rob Austein
+ * Copyright (c) 2015, SUNET
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SQL_COMMON_H_
+#define _SQL_COMMON_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include <sqlite3.h>
+
+/*
+ * Placeholders for PIN length limits. Figure out real values later.
+ */
+
+#warning Figure out PIN length limits
+#define P11_MIN_PIN_LENGTH 16
+#define P11_MAX_PIN_LENGTH 4096
+
+/*
+ * 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;
+}
+
+#endif /* _SQL_COMMON_H_ */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */