[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