[Cryptech-Commits] [sw/pkcs11] 02/04: p11util now uses libhal and doesn't need to touch SQL.
git at cryptech.is
git at cryptech.is
Fri May 13 01:48:45 UTC 2016
This is an automated email from the git hooks/post-receive script.
sra at hactrn.net pushed a commit to branch rpc
in repository sw/pkcs11.
commit 63d3f7f29aecf00468025c05bc01723360d86e24
Author: Rob Austein <sra at hactrn.net>
AuthorDate: Thu May 12 16:13:00 2016 -0400
p11util now uses libhal and doesn't need to touch SQL.
"p11util" is now something of a misnomer, since there's no longer
anything about it that's specific to PKCS #11. Probably should become
a libhal utility program, eventually.
---
GNUmakefile | 4 +-
p11_common.h | 61 ++++++++++++++
p11util.c | 160 +++++++++++++-----------------------
pkcs11.c | 200 ++++++++++++++++++++++++++++++++++++++++++++-
sql_common.h | 259 -----------------------------------------------------------
5 files changed, 319 insertions(+), 365 deletions(-)
diff --git a/GNUmakefile b/GNUmakefile
index 90440a7..71ca871 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -96,7 +96,7 @@ attributes.h: attributes.yaml scripts/build-attributes GNUmakefile
py11/attribute_map.py: attributes.yaml scripts/build-py11-attributes GNUmakefile
python scripts/build-py11-attributes attributes.yaml py11/attribute_map.py
-pkcs11.o: pkcs11.c sql_common.h schema.h attributes.h
+pkcs11.o: pkcs11.c p11_common.h schema.h attributes.h
${CC} ${CFLAGS} -c $<
pkcs11.so: pkcs11.o ${LIBS}
@@ -105,7 +105,7 @@ pkcs11.so: pkcs11.o ${LIBS}
libpkcs11.so: pkcs11.so
${OBJCOPY} -w -G 'C_*' $< $@
-p11util.o: p11util.c sql_common.h schema.h
+p11util.o: p11util.c p11_common.h schema.h
${CC} ${CFLAGS} -c $<
p11util: p11util.o ${LIBS}
diff --git a/p11_common.h b/p11_common.h
new file mode 100644
index 0000000..898e087
--- /dev/null
+++ b/p11_common.h
@@ -0,0 +1,61 @@
+/*
+ * p11_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, NORDUnet A/S
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the NORDUnet nor the names of its contributors may
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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
+ * HOLDER 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 _P11_COMMON_H_
+#define _P11_COMMON_H_
+
+/*
+ * Placeholders for PIN length limits. Figure out real values later.
+ * Minimum length here is much too short, we allow it for now because
+ * some test programs fail if we insist on a reasonable length.
+ */
+
+#warning Figure out PIN length limits
+#define P11_MIN_PIN_LENGTH 4
+#define P11_MAX_PIN_LENGTH 4096
+
+#endif /* _P11_COMMON_H_ */
+
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/p11util.c b/p11util.c
index a08cb14..606e40c 100644
--- a/p11util.c
+++ b/p11util.c
@@ -47,7 +47,7 @@
#include <hal.h>
-#include "sql_common.h"
+#include "p11_common.h"
/*
* Apparently the cool kids don't use getpassword() anymore, and there
@@ -114,7 +114,7 @@ static int getpin_tty(const char *prompt,
OPT_FLG('h', "help", "show help") \
OPT_FLG('s', "set-so-pin", "set Security Officer PIN") \
OPT_FLG('u', "set-user-pin", "set \"user\" PIN") \
- OPT_ARG('i', "set-iterations", "set PBKDF2 iteration count") \
+ OPT_FLG('w', "set-wheel-pin", "set \"wheel\" PIN") \
OPT_FLG('p', "pin-from-stdin", "read PIN from stdin instead of /dev/tty") \
OPT_END
@@ -139,11 +139,9 @@ static void usage(const int code, const char *jane)
static void parse_args(int argc, char *argv[],
int *do_set_so_pin,
int *do_set_user_pin,
- int *do_set_iterations,
- int *read_from_stdin,
- unsigned long *iterations)
+ int *do_set_wheel_pin,
+ int *read_from_stdin)
{
- char *endptr;
int c;
#define OPT_FLG(_short_, _long_, _help_) _short_,
@@ -158,9 +156,7 @@ static void parse_args(int argc, char *argv[],
#undef OPT_ARG
#undef OPT_FLG
- assert(argv != 0 &&
- do_set_so_pin != 0 && do_set_user_pin != 0 && do_set_iterations != NULL &&
- read_from_stdin != NULL && iterations != NULL);
+ assert(argv && do_set_so_pin && do_set_user_pin && do_set_wheel_pin && read_from_stdin);
opterr = 0;
if (argc == 1)
@@ -172,13 +168,6 @@ static void parse_args(int argc, char *argv[],
case 'h':
usage(0, argv[0]);
- case 'i':
- *do_set_iterations = 1;
- *iterations = strtoul(optarg, &endptr, 0);
- if (*optarg == '\0' || *endptr != '\0')
- usage(1, argv[0]);
- continue;
-
case 'p':
*read_from_stdin = 1;
continue;
@@ -191,6 +180,10 @@ static void parse_args(int argc, char *argv[],
*do_set_user_pin = 1;
continue;
+ case 'w':
+ *do_set_wheel_pin = 1;
+ continue;
+
default:
usage(1, argv[0]);
}
@@ -202,47 +195,31 @@ static void parse_args(int argc, char *argv[],
-#define lose(_msg_) \
- do { \
- fprintf(stderr, "%s\n", _msg_); \
- goto fail; \
- } while (0)
-
-static int set_iterations(unsigned long iterations)
+static int set_pin(const hal_user_t user, const int read_from_stdin)
{
- static const char update_query[] =
- " UPDATE global SET pbkdf2_iterations = ?";
+ const char *prompt = NULL, *label = NULL;
+ char pin[P11_MAX_PIN_LENGTH + 1], *p;
- sqlite3_stmt *q = NULL;
- int ok = 0;
+ switch (user) {
- if (!sql_check_ok(sql_prepare(&q, update_query)) ||
- !sql_check_ok(sqlite3_bind_int64(q, 1, iterations)) ||
- !sql_check_done(sqlite3_step(q)))
- lose("Couldn't update database");
+ case HAL_USER_NORMAL:
+ prompt = "Enter user PIN: ";
+ label = "user";
+ break;
- ok = 1;
+ case HAL_USER_SO:
+ prompt = "Enter SO PIN: ";
+ label = "SO";
+ break;
- fail:
- sqlite3_finalize(q);
- return ok;
-}
+ case HAL_USER_WHEEL:
+ prompt = "Enter wheel PIN: ";
+ label = "wheel";
+ break;
-static int set_pin(const char * const pin_type, const int read_from_stdin)
-{
- static const char iterations_query[] =
- " SELECT pbkdf2_iterations FROM global";
-
- static const char update_format[] =
- " UPDATE global SET %s_pin = ?1, %s_pin_salt = ?2";
-
- /* Allow user to change these lengths? */
- uint8_t pinbuf[32], salt[16];
-
- char pin[P11_MAX_PIN_LENGTH + 1], *p;
- sqlite3_stmt *q = NULL;
- hal_error_t err;
- int ok = 0;
+ default:
+ return 0;
+ }
if (read_from_stdin) {
if (fgets(pin, sizeof(pin), stdin) == NULL) {
@@ -254,8 +231,6 @@ static int set_pin(const char * const pin_type, const int read_from_stdin)
}
else {
- char prompt[sizeof("Enter user PIN: ")];
- snprintf(prompt, sizeof(prompt), "Enter %s PIN: ", pin_type);
if (!getpin_tty(prompt, pin, sizeof(pin)))
return 0;
}
@@ -263,73 +238,52 @@ static int set_pin(const char * const pin_type, const int read_from_stdin)
const size_t len = strlen(pin);
if (len < P11_MIN_PIN_LENGTH || len > P11_MAX_PIN_LENGTH) {
- fprintf(stderr, "Unacceptable length %lu for %s PIN, allowd range [%lu, %lu]\n",
- (unsigned long) len, pin_type,
- (unsigned long) P11_MIN_PIN_LENGTH, (unsigned long) P11_MAX_PIN_LENGTH);
+ fprintf(stderr, "Unacceptable length %lu for %s PIN, allowed range [%lu, %lu]\n",
+ (unsigned long) len, label,
+ (unsigned long) P11_MIN_PIN_LENGTH,
+ (unsigned long) P11_MAX_PIN_LENGTH);
+ memset(pin, 0, sizeof(pin));
return 0;
}
- if (!sql_check_ok(sql_prepare(&q, iterations_query)) ||
- !sql_check_row(sqlite3_step(q)) ||
- sqlite3_column_type(q, 0) == SQLITE_NULL)
- lose("Couldn't retrieve PBKDF2 iteration count from SQL");
+ const hal_client_handle_t client = {HAL_HANDLE_NONE};
- if ((err = hal_get_random(NULL, salt, sizeof(salt))) != HAL_OK) {
- fprintf(stderr, "Couldn't generate salt: %s\n", hal_error_string(err));
- goto fail;
- }
+ const hal_error_t err = hal_rpc_set_pin(client, user, pin, len);
- if ((err = hal_pbkdf2(NULL, hal_hash_sha256, (uint8_t *) pin, len, salt, sizeof(salt),
- pinbuf, sizeof(pinbuf), sqlite3_column_int(q, 0))) != HAL_OK) {
- fprintf(stderr, "Couldn't process new PIN: %s\n", hal_error_string(err));
- goto fail;
+ if (err != HAL_OK) {
+ fprintf(stderr, "Couldn't set %s PIN: %s\n", label, hal_error_string(err));
+ memset(pin, 0, sizeof(pin));
+ return 0;
}
- if (!sql_check_ok(sql_finalize_and_clear(&q)) ||
- !sql_check_ok(sql_prepare(&q, update_format, pin_type, pin_type)) ||
- !sql_check_ok(sqlite3_bind_blob(q, 1, pinbuf, sizeof(pinbuf), NULL)) ||
- !sql_check_ok(sqlite3_bind_blob(q, 2, salt, sizeof(salt), NULL)) ||
- !sql_check_done(sqlite3_step(q)))
- lose("Couldn't update database");
-
- ok = 1;
-
- fail:
- sqlite3_finalize(q);
memset(pin, 0, sizeof(pin));
- memset(pinbuf, 0, sizeof(pinbuf));
- memset(salt, 0, sizeof(salt));
- return ok;
+ return 1;
}
+
+
int main(int argc, char *argv[])
{
- int do_set_so_pin = 0, do_set_user_pin = 0, do_set_iterations = 0, read_from_stdin = 0;
- unsigned long iterations;
- int ok = 0;
-
- parse_args(argc, argv, &do_set_so_pin, &do_set_user_pin, &do_set_iterations, &read_from_stdin, &iterations);
-
- if (!sql_init() || !sql_exec("BEGIN"))
- lose("Couldn't initialize SQL, giving up");
-
- if (do_set_iterations && !set_iterations(iterations))
- lose("Couldn't set PBKDF2 iteration count");
+ int do_set_so_pin = 0, do_set_user_pin = 0, do_set_wheel_pin = 0, read_from_stdin = 0;
- if (do_set_so_pin && !set_pin("so", read_from_stdin))
- lose("Couldn't set SO PIN");
+ parse_args(argc, argv, &do_set_so_pin, &do_set_user_pin, &do_set_wheel_pin, &read_from_stdin);
- if (do_set_user_pin && !set_pin("user", read_from_stdin))
- lose("Couldn't set user PIN");
+ if (do_set_wheel_pin && !set_pin(HAL_USER_WHEEL, read_from_stdin)) {
+ fprintf(stderr, "Couldn't set wheel PIN\n");
+ return 1;
+ }
- if (!sql_exec("COMMIT"))
- lose("Couldn't commit SQL transaction");
+ if (do_set_so_pin && !set_pin(HAL_USER_SO, read_from_stdin)) {
+ fprintf(stderr, "Couldn't set SO PIN\n");
+ return 2;
+ }
- ok = 1;
+ if (do_set_user_pin && !set_pin(HAL_USER_NORMAL, read_from_stdin)) {
+ fprintf(stderr, "Couldn't set user PIN\n");
+ return 3;
+ }
- fail:
- sql_fini();
- return !ok;
+ return 0;
}
/*
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;
diff --git a/sql_common.h b/sql_common.h
deleted file mode 100644
index b8c7740..0000000
--- a/sql_common.h
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * 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, NORDUnet A/S
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - 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.
- *
- * - Neither the name of the NORDUnet nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * 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
- * HOLDER 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.
- * Minimum length here is much too short, we allow it for now because
- * some test programs fail if we insist on a reasonable length.
- */
-
-#warning Figure out PIN length limits
-#define P11_MIN_PIN_LENGTH 4
-#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:
- */
More information about the Commits
mailing list