summaryrefslogtreecommitdiff
path: root/src/common/db/gsignond-db-secret-database.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/db/gsignond-db-secret-database.c')
-rw-r--r--src/common/db/gsignond-db-secret-database.c437
1 files changed, 437 insertions, 0 deletions
diff --git a/src/common/db/gsignond-db-secret-database.c b/src/common/db/gsignond-db-secret-database.c
new file mode 100644
index 0000000..51fa0da
--- /dev/null
+++ b/src/common/db/gsignond-db-secret-database.c
@@ -0,0 +1,437 @@
+/* vi: set et sw=4 ts=4 cino=t0,(0: */
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of gsignond
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Contact: Imran Zaman <imran.zaman@linux.intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <sqlite3.h>
+#include <string.h>
+
+#include "gsignond/gsignond-log.h"
+#include "gsignond-db-error.h"
+#include "gsignond-db-defines.h"
+#include "gsignond-db-secret-database.h"
+#include "gsignond-db-sql-database-private.h"
+
+#define RETURN_IF_NOT_OPEN(obj, retval) \
+ if (gsignond_db_sql_database_is_open ( \
+ GSIGNOND_DB_SQL_DATABASE (obj)) == FALSE) { \
+ GError* last_error = gsignond_db_create_error( \
+ GSIGNOND_DB_ERROR_NOT_OPEN,\
+ "DB Not Open"); \
+ DBG("SecretDB is not available"); \
+ gsignond_db_sql_database_set_last_error( \
+ GSIGNOND_DB_SQL_DATABASE (obj), last_error); \
+ return retval; \
+ }
+
+#define GSIGNOND_DB_SECRET_DATABASE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+ GSIGNOND_DB_TYPE_SECRET_DATABASE, \
+ GSignondDbSecretDatabasePrivate))
+
+G_DEFINE_TYPE (GSignondDbSecretDatabase, gsignond_db_secret_database,
+ GSIGNOND_DB_TYPE_SQL_DATABASE);
+
+struct _GSignondDbSecretDatabasePrivate
+{
+};
+
+static gboolean
+gsignond_db_secret_database_create (GSignondDbSqlDatabase *obj);
+
+static gboolean
+gsignond_db_secret_database_clear (GSignondDbSqlDatabase *obj);
+
+static gboolean
+_gsignond_db_read_username_password (
+ sqlite3_stmt *stmt,
+ GSignondCredentials *creds)
+{
+ gsignond_credentials_set_username (creds,
+ (const gchar *)sqlite3_column_text (stmt, 0));
+
+ gsignond_credentials_set_password (creds,
+ (const gchar *)sqlite3_column_text (stmt, 1));
+
+ return TRUE;
+}
+
+static gboolean
+_gsignond_db_read_key_value (
+ sqlite3_stmt *stmt,
+ GSignondDictionary* data)
+{
+ const gchar *key = NULL;
+ GVariant *value = NULL;
+ key = (const gchar *)sqlite3_column_text (stmt, 0);
+ value = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
+ (gconstpointer) sqlite3_column_blob(stmt, 1),
+ (gsize) sqlite3_column_bytes(stmt, 1), sizeof(guchar));
+
+ gsignond_dictionary_set (data, key, value);
+ return TRUE;
+}
+
+
+static void
+_gsignond_db_secret_database_finalize (GObject *gobject)
+{
+ /* Chain up to the parent class */
+ G_OBJECT_CLASS (gsignond_db_secret_database_parent_class)->finalize (
+ gobject);
+}
+
+static void
+gsignond_db_secret_database_class_init (GSignondDbSecretDatabaseClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = _gsignond_db_secret_database_finalize;
+
+ GSignondDbSqlDatabaseClass *sql_class =
+ GSIGNOND_DB_SQL_DATABASE_CLASS (klass);
+
+ sql_class->create = gsignond_db_secret_database_create;
+ sql_class->clear = gsignond_db_secret_database_clear;
+
+}
+
+static void
+gsignond_db_secret_database_init (GSignondDbSecretDatabase *self)
+{
+ /*self->priv = GSIGNOND_DB_SECRET_DATABASE_GET_PRIVATE (self);*/
+}
+
+/**
+ * gsignond_db_secret_database_new:
+ *
+ * Creates new #GSignondDbSecretDatabase object
+ * Returns : (transfer full) the #GSignondDbSecretDatabase object
+ *
+ */
+GSignondDbSecretDatabase *
+gsignond_db_secret_database_new ()
+{
+ return GSIGNOND_DB_SECRET_DATABASE (
+ g_object_new (GSIGNOND_DB_TYPE_SECRET_DATABASE,
+ NULL));
+}
+
+static gboolean
+gsignond_db_secret_database_create (GSignondDbSqlDatabase *obj)
+{
+ const gchar *queries = NULL;
+ g_return_val_if_fail (GSIGNOND_DB_IS_SECRET_DATABASE (obj), FALSE);
+ RETURN_IF_NOT_OPEN (GSIGNOND_DB_SECRET_DATABASE (obj), FALSE);
+
+ if (gsignond_db_sql_database_get_db_version(obj,
+ "PRAGMA user_version;") > 0) {
+ DBG ("DB is already created");
+ return TRUE;
+ }
+
+ queries = ""
+ "CREATE TABLE IF NOT EXISTS CREDENTIALS"
+ "(id INTEGER NOT NULL UNIQUE,"
+ "username TEXT,"
+ "password TEXT,"
+ "PRIMARY KEY (id));"
+
+ "CREATE TABLE IF NOT EXISTS STORE"
+ "(identity_id INTEGER,"
+ "method_id INTEGER,"
+ "key TEXT,"
+ "value BLOB,"
+ "PRIMARY KEY (identity_id, method_id, key));"
+
+ "CREATE TRIGGER IF NOT EXISTS tg_delete_credentials "
+ "BEFORE DELETE ON CREDENTIALS "
+ "FOR EACH ROW BEGIN "
+ " DELETE FROM STORE WHERE STORE.identity_id = OLD.id; "
+ "END; "
+
+ "PRAGMA user_version = 1;";
+
+ return gsignond_db_sql_database_transaction_exec (obj, queries);
+}
+
+static gboolean
+gsignond_db_secret_database_clear (GSignondDbSqlDatabase *obj)
+{
+ const gchar *queries = NULL;
+
+ g_return_val_if_fail (GSIGNOND_DB_IS_SECRET_DATABASE (obj), FALSE);
+ RETURN_IF_NOT_OPEN (GSIGNOND_DB_SECRET_DATABASE (obj), FALSE);
+
+ queries = ""
+ "DELETE FROM CREDENTIALS;"
+ "DELETE FROM STORE;";
+
+ return gsignond_db_sql_database_transaction_exec (obj, queries);
+}
+
+GSignondCredentials*
+gsignond_db_secret_database_load_credentials (
+ GSignondDbSecretDatabase *self,
+ const guint32 id)
+{
+ gchar *query = NULL;
+ gint rows = 0;
+ GSignondCredentials *creds = NULL;
+
+ g_return_val_if_fail (GSIGNOND_DB_IS_SECRET_DATABASE (self), NULL);
+ RETURN_IF_NOT_OPEN (self, NULL);
+
+ creds = gsignond_credentials_new ();
+ query = sqlite3_mprintf ("SELECT username, password FROM credentials "
+ "WHERE id = %u limit 1",
+ id);
+ rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
+ query,
+ (GSignondDbSqlDatabaseQueryCallback)
+ _gsignond_db_read_username_password,
+ creds);
+ sqlite3_free (query);
+
+ if (G_UNLIKELY (rows <= 0)) {
+ DBG ("Load credentials from DB failed");
+ g_object_unref (creds);
+ creds = NULL;
+ } else {
+ gsignond_credentials_set_id (creds, id);
+ }
+ return creds;
+}
+
+gboolean
+gsignond_db_secret_database_update_credentials (
+ GSignondDbSecretDatabase *self,
+ GSignondCredentials *creds)
+{
+ gchar *query = NULL;
+ gboolean ret = FALSE;
+ guint32 id = 0;
+ const gchar *username = NULL;
+ const gchar *password = NULL;
+
+ g_return_val_if_fail (GSIGNOND_DB_IS_SECRET_DATABASE (self), FALSE);
+ RETURN_IF_NOT_OPEN (self, FALSE);
+
+ id = gsignond_credentials_get_id (creds);
+ username = gsignond_credentials_get_username (creds);
+ password = gsignond_credentials_get_password (creds);
+ query = sqlite3_mprintf ("INSERT OR REPLACE INTO CREDENTIALS "
+ "(id, username, password) "
+ "VALUES (%u, %Q, %Q);",
+ id, username ? username : "",
+ password ? password : "");
+ ret = gsignond_db_sql_database_transaction_exec (
+ GSIGNOND_DB_SQL_DATABASE (self), query);
+ sqlite3_free (query);
+
+ return ret;
+}
+
+gboolean
+gsignond_db_secret_database_remove_credentials (
+ GSignondDbSecretDatabase *self,
+ const guint32 id)
+{
+ gchar *query = NULL;
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (GSIGNOND_DB_IS_SECRET_DATABASE (self), FALSE);
+ RETURN_IF_NOT_OPEN (self, FALSE);
+
+ query = sqlite3_mprintf ("DELETE FROM CREDENTIALS WHERE id = %u;"
+ "DELETE FROM STORE WHERE identity_id = %u;",
+ id, id);
+ ret = gsignond_db_sql_database_transaction_exec (
+ GSIGNOND_DB_SQL_DATABASE (self), query);
+ sqlite3_free (query);
+ return ret;
+}
+
+GSignondDictionary *
+gsignond_db_secret_database_load_data (
+ GSignondDbSecretDatabase *self,
+ const guint32 id,
+ const guint32 method)
+{
+ gchar *query = NULL;
+ gint rows = 0;
+ GSignondDictionary *data = NULL;
+
+ g_return_val_if_fail (GSIGNOND_DB_IS_SECRET_DATABASE (self), NULL);
+ RETURN_IF_NOT_OPEN (self, NULL);
+
+ data = gsignond_dictionary_new ();
+
+ query = sqlite3_mprintf (
+ "SELECT key, value "
+ "FROM STORE WHERE identity_id = %u AND method_id = %u",
+ id, method);
+
+ rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
+ query,
+ (GSignondDbSqlDatabaseQueryCallback)_gsignond_db_read_key_value,
+ data);
+
+ sqlite3_free (query);
+
+ if (G_UNLIKELY (rows <= 0)) {
+ DBG ("Load data from DB failed");
+ gsignond_dictionary_unref (data);
+ data = NULL;
+ }
+
+ return data;
+}
+
+gboolean
+gsignond_db_secret_database_update_data (
+ GSignondDbSecretDatabase *self,
+ const guint32 id,
+ const guint32 method,
+ GSignondDictionary *data)
+{
+ gchar *query = NULL;
+ gint ret = 0;
+ GHashTableIter iter;
+ gchar *key = NULL;
+ GVariant *value = NULL;
+ guint32 data_counter = 0;
+ GSignondDbSqlDatabase *parent = NULL;
+
+ g_return_val_if_fail (GSIGNOND_DB_IS_SECRET_DATABASE (self), FALSE);
+ RETURN_IF_NOT_OPEN (self, FALSE);
+ g_return_val_if_fail (data != NULL, FALSE);
+
+ parent = GSIGNOND_DB_SQL_DATABASE (self);
+ if (!gsignond_db_sql_database_start_transaction (parent)) {
+ DBG ("Start DB transaction Failed");
+ return FALSE;
+ }
+
+ /* First, remove existing data */
+ query = sqlite3_mprintf (
+ "DELETE FROM STORE WHERE identity_id = %u ",
+ "AND method_id = %u;",
+ id, method);
+ ret = sqlite3_exec (parent->priv->db, query, NULL, NULL, NULL);
+ sqlite3_free (query);
+ if (G_UNLIKELY (ret != SQLITE_OK)) {
+ DBG ("Delete old data from DB Failed");
+ gsignond_db_sql_database_update_error_from_db (parent);
+ gsignond_db_sql_database_rollback_transaction (parent);
+ return FALSE;
+ }
+
+ /* Check if the size requirement is met before running any queries */
+ g_hash_table_iter_init (&iter, data);
+ while (g_hash_table_iter_next (&iter,(gpointer *) &key,
+ (gpointer *) &value)) {
+ data_counter = data_counter + strlen (key) + g_variant_get_size(value);
+ if (data_counter >= GSIGNOND_DB_MAX_DATA_STORAGE) {
+ gsignond_db_sql_database_rollback_transaction (parent);
+ DBG ("size limit is exceeded");
+ return FALSE;
+ }
+ }
+
+ /* Insert data to db */
+ const char* statement = "INSERT OR REPLACE INTO STORE "
+ "(identity_id, method_id, key, value) "
+ "VALUES(?, ?, ?, ?)";
+ g_hash_table_iter_init (&iter, data);
+ while (g_hash_table_iter_next (&iter, (gpointer *)&key,
+ (gpointer *) &value )) {
+ gsize val_size;
+ gconstpointer value_data;
+ sqlite3_stmt *sql_stmt;
+
+ ret = sqlite3_prepare_v2 (parent->priv->db, statement, -1,
+ &sql_stmt, NULL);
+ if (G_UNLIKELY (ret != SQLITE_OK)) {
+ DBG ("Data Insertion to DB Failed");
+ gsignond_db_sql_database_update_error_from_db (parent);
+ gsignond_db_sql_database_rollback_transaction (parent);
+ return FALSE;
+ }
+ value_data = g_variant_get_data (value);
+ val_size = g_variant_get_size (value);
+
+ sqlite3_bind_int(sql_stmt, 1, (int)id);
+ sqlite3_bind_int(sql_stmt, 2, (int)method);
+ sqlite3_bind_text(sql_stmt, 3, key, -1, SQLITE_STATIC);
+ sqlite3_bind_blob(sql_stmt, 4, value_data, (int)val_size, SQLITE_STATIC);
+
+ ret = sqlite3_step (sql_stmt);
+ if (G_UNLIKELY (ret != SQLITE_DONE)) {
+ DBG ("Data Insertion to DB Failed");
+ gsignond_db_sql_database_update_error_from_db (parent);
+ gsignond_db_sql_database_rollback_transaction (parent);
+ return FALSE;
+ }
+
+ ret = sqlite3_finalize (sql_stmt);
+ if (G_UNLIKELY (ret != SQLITE_OK)) {
+ DBG ("Data Insertion to DB Failed");
+ gsignond_db_sql_database_update_error_from_db (parent);
+ gsignond_db_sql_database_rollback_transaction (parent);
+ return FALSE;
+ }
+ }
+
+ return gsignond_db_sql_database_commit_transaction (parent);
+}
+
+gboolean
+gsignond_db_secret_database_remove_data (
+ GSignondDbSecretDatabase *self,
+ const guint32 id,
+ const guint32 method)
+{
+ gchar *statement = NULL;
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (GSIGNOND_DB_IS_SECRET_DATABASE (self), FALSE);
+ RETURN_IF_NOT_OPEN (self, FALSE);
+
+ if (method == 0) {
+ DBG ("Delete data from DB based on identity id only as method id is 0");
+ statement = sqlite3_mprintf (
+ "DELETE FROM STORE WHERE identity_id = %u;",
+ id);
+ } else {
+ statement = sqlite3_mprintf (
+ "DELETE FROM STORE WHERE identity_id = %u ",
+ "AND method_id = %u;",
+ id, method);
+ }
+ ret = gsignond_db_sql_database_transaction_exec (
+ GSIGNOND_DB_SQL_DATABASE (self), statement);
+ sqlite3_free (statement);
+
+ return ret;
+}
+