aboutsummaryrefslogblamecommitdiff
path: root/sql_common.h
blob: b8c7740e3c15d8ceea3c486db12ef2b31751b563 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
  









                                                                        

                                   
  




                                                                           
  


                                                                         
  


                                                                           
  










                                                                           







                      
                   





                                                                     

                                                                     


                                     
                                 






































































































































































































                                                                         
/*
 * 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:
 */