8b76b3aa3213b6fbd9b968db94ed960d67e9de2c
[profile/ivi/gsignond.git] / src / daemon / db / gsignond-db-metadata-database.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2012 Intel Corporation.
7  *
8  * Contact: Imran Zaman <imran.zaman@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25 #if HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 #include <string.h>
29 #include <sys/stat.h>
30
31 #include "gsignond/gsignond-log.h"
32 #include "gsignond/gsignond-config.h"
33 #include "common/db/gsignond-db-error.h"
34 #include "gsignond-db-metadata-database.h"
35
36 #define RETURN_IF_NOT_OPEN(obj, retval) \
37     if (gsignond_db_sql_database_is_open (obj) == FALSE) { \
38         GError* last_error = gsignond_db_create_error( \
39                             GSIGNOND_DB_ERROR_NOT_OPEN,\
40                             "DB Not Open"); \
41         DBG("MetadataDB is not available"); \
42         gsignond_db_sql_database_set_last_error(obj,\
43                                                 last_error); \
44         return retval; \
45     }
46
47 #define GSIGNOND_DB_METADATA_DATABASE_GET_PRIVATE(obj) \
48                                           (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
49                                            GSIGNOND_DB_TYPE_METADATA_DATABASE, \
50                                            GSignondDbMetadataDatabasePrivate))
51
52 G_DEFINE_TYPE (GSignondDbMetadataDatabase, gsignond_db_metadata_database,
53         GSIGNOND_DB_TYPE_SQL_DATABASE);
54
55 struct _GSignondDbMetadataDatabasePrivate
56 {
57 };
58
59 enum
60 {
61     PROP_0,
62     PROP_CONFIG,
63     N_PROPERTIES
64 };
65
66 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
67
68 static void
69 _set_property (GObject *object, guint prop_id, const GValue *value,
70                GParamSpec *pspec)
71 {
72     GSignondDbMetadataDatabase *self = GSIGNOND_DB_METADATA_DATABASE (object);
73
74     switch (prop_id) {
75         case PROP_CONFIG:
76             g_assert (self->config == NULL);
77             self->config = g_value_dup_object (value);
78             break;
79         default:
80             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
81     }
82 }
83
84 static void
85 _get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
86 {
87     GSignondDbMetadataDatabase *self = GSIGNOND_DB_METADATA_DATABASE (object);
88
89     switch (prop_id) {
90         case PROP_CONFIG:
91             g_value_set_object (value, self->config);
92             break;
93         default:
94             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
95     }
96 }
97
98 static gboolean
99 _gsignond_db_metadata_database_open (
100         GSignondDbSqlDatabase *obj,
101         const gchar *filename,
102         int flags);
103
104 static gboolean
105 _gsignond_db_metadata_database_create (
106         GSignondDbSqlDatabase *obj);
107
108 static gboolean
109 _gsignond_db_metadata_database_clear (
110         GSignondDbSqlDatabase *obj);
111
112 /*!
113  * @enum GSignondIdentityFlags
114  * Flags for the identity to be stored into db
115  */
116 enum GSignondIdentityFlags {
117     GSignondIdentityFlag_Validated = 0x0001,
118     GSignondIdentityFlag_RememberSecret = 0x0002,
119     GSignondIdentityFlag_UserNameIsSecret = 0x0004,
120 };
121
122 static gint
123 _compare_strings (
124                 const gchar* a,
125                 const gchar* b,
126                 gpointer data)
127 {
128         (void)data;
129         return g_strcmp0 (a,b);
130 }
131
132 static GSequence *
133 _gsignond_db_metadata_database_list_to_sequence (GList *list)
134 {
135     GSequence *seq = NULL;
136     seq = g_sequence_new ((GDestroyNotify)g_free);
137     list = g_list_first (list);
138     for ( ; list != NULL; list = g_list_next (list)) {
139         g_sequence_insert_sorted (seq, (gchar *) list->data,
140                         (GCompareDataFunc)_compare_strings, NULL);
141     }
142     return seq;
143 }
144
145 static gboolean
146 _gsignond_db_metadata_database_read_identity (
147         sqlite3_stmt *stmt,
148         GSignondIdentityInfo *identity)
149 {
150     gint flags = 0;
151
152     gsignond_identity_info_set_caption (identity,
153             (const gchar *)sqlite3_column_text (stmt, 0));
154
155     flags = sqlite3_column_int (stmt, 2);
156
157     gsignond_identity_info_set_username_secret (identity,
158           flags & GSignondIdentityFlag_UserNameIsSecret);
159
160     if (flags & GSignondIdentityFlag_UserNameIsSecret) {
161         gsignond_identity_info_set_caption (identity, "");
162     } else {
163         gsignond_identity_info_set_username (identity,
164                     (const gchar *)sqlite3_column_text (stmt, 1));
165     }
166
167     gsignond_identity_info_set_store_secret (identity,
168             flags & GSignondIdentityFlag_RememberSecret);
169
170     gsignond_identity_info_set_validated (identity,
171             flags & GSignondIdentityFlag_Validated);
172
173     gsignond_identity_info_set_identity_type (identity,
174             sqlite3_column_int (stmt, 3));
175
176     return TRUE;
177 }
178
179 static gboolean
180 _gsignond_db_metadata_database_exec (
181         GSignondDbMetadataDatabase *self,
182         const gchar *query_format,
183         ...)
184 {
185     gboolean ret = FALSE;
186     gchar *query = NULL;
187     va_list args;
188
189     g_return_val_if_fail (query_format != NULL, FALSE);
190
191     va_start (args, query_format);
192     query = sqlite3_vmprintf (query_format, args);
193     va_end (args);
194
195     ret = gsignond_db_sql_database_exec (
196                     GSIGNOND_DB_SQL_DATABASE (self),
197                     query);
198     sqlite3_free (query);
199
200     return ret;
201 }
202
203
204 static GSequence *
205 _gsignond_db_metadata_database_get_sequence (
206         GSignondDbMetadataDatabase *self,
207         const gchar *query_format,
208         ...)
209 {
210     GSequence *seq = NULL;
211     GList *list = NULL;
212     gchar *query = NULL;
213     va_list args;
214
215     g_return_val_if_fail (query_format != NULL, NULL);
216
217     va_start (args, query_format);
218     query = sqlite3_vmprintf (query_format, args);
219     va_end (args);
220
221     list = gsignond_db_sql_database_query_exec_string_list (
222                     GSIGNOND_DB_SQL_DATABASE (self),
223                     query);
224     sqlite3_free (query);
225     seq = _gsignond_db_metadata_database_list_to_sequence (list);
226     g_list_free (list); /*list elements are owned by sequence*/
227
228     return seq;
229 }
230
231 guint32
232 _gsignond_db_metadata_database_update_credentials (
233         GSignondDbMetadataDatabase *self,
234         GSignondIdentityInfo *identity)
235 {
236     gchar *query = NULL;
237     gint flags = 0;
238     guint32 type;
239     gint64 id;
240     const gchar *caption= NULL, *username = NULL;
241     gboolean ret = FALSE;
242
243     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), 0);
244     g_return_val_if_fail (identity != NULL, 0);
245
246     if (gsignond_identity_info_get_validated (identity) )
247         flags |= GSignondIdentityFlag_Validated;
248     if (gsignond_identity_info_get_store_secret (identity) )
249         flags |= GSignondIdentityFlag_RememberSecret;
250     if (gsignond_identity_info_get_is_username_secret (identity) ) {
251         flags |= GSignondIdentityFlag_UserNameIsSecret;
252     } else {
253         username = gsignond_identity_info_get_username (identity);
254     }
255     caption = gsignond_identity_info_get_caption (identity);
256
257     id = gsignond_identity_info_get_id (identity);
258     type = gsignond_identity_info_get_identity_type (identity);
259     if (!gsignond_identity_info_get_is_identity_new (identity)) {
260         query = sqlite3_mprintf ("UPDATE IDENTITY SET caption = %Q, "
261                 "username = %Q, flags = %u, type = %u WHERE id = %u;",
262                 caption ?caption : "",username? username : "", flags, type, id);
263     } else {
264         query = sqlite3_mprintf ("INSERT INTO IDENTITY "
265                 "(caption, username, flags, type) "
266                 "VALUES(%Q, %Q, %u, %u);",
267                 caption ?caption : "",username? username : "", flags, type);
268     }
269     ret = gsignond_db_sql_database_exec (
270                 GSIGNOND_DB_SQL_DATABASE (self),
271                 query);
272     sqlite3_free (query);
273     if (!ret) {
274         return 0;
275     }
276
277     if (gsignond_identity_info_get_is_identity_new (identity)) {
278         id = gsignond_db_sql_database_get_last_insert_rowid (
279                     GSIGNOND_DB_SQL_DATABASE (self));
280     }
281     return (guint32)id;
282 }
283
284 gboolean
285 _gsignond_db_metadata_database_update_realms (
286         GSignondDbMetadataDatabase *self,
287         GSignondIdentityInfo *identity,
288         guint32 id,
289         GSequence *realms)
290 {
291     GSequenceIter *iter = NULL;
292
293     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
294     g_return_val_if_fail (identity != NULL, FALSE);
295
296     if (realms && g_sequence_get_length (realms) > 0) {
297
298         if (!gsignond_identity_info_get_is_identity_new (identity)) {
299             /* remove realms list */
300             DBG ("Remove old realms from DB as identity is not new");
301             _gsignond_db_metadata_database_exec (self,
302                     "DELETE FROM REALMS WHERE identity_id = %u;", id);
303         }
304
305         /* realms insert */
306         iter = g_sequence_get_begin_iter (realms);
307         while (!g_sequence_iter_is_end (iter)) {
308             if (!_gsignond_db_metadata_database_exec (self,
309                     "INSERT OR IGNORE INTO REALMS (identity_id, realm) "
310                     "VALUES (%u, %Q);",
311                     id, (const gchar *)g_sequence_get (iter))) {
312                 DBG ("Insert realms to DB failed");
313                 return FALSE;
314             }
315             iter = g_sequence_iter_next (iter);
316         }
317     }
318     return TRUE;
319 }
320
321 gboolean
322 _gsignond_db_metadata_database_insert_methods (
323         GSignondDbMetadataDatabase *self,
324         GSignondIdentityInfo *identity,
325         GHashTable *methods)
326 {
327     GSequenceIter *mech_iter = NULL;
328     GHashTableIter method_iter;
329     const gchar *method = NULL;
330     GSequence *mechanisms = NULL;
331
332     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
333     g_return_val_if_fail (identity != NULL, FALSE);
334
335     if (!methods || g_hash_table_size (methods) <=0) {
336         DBG ("no authentication methods found to store identity");
337         return FALSE;
338     }
339
340     g_hash_table_iter_init (&method_iter, methods);
341     while (g_hash_table_iter_next (&method_iter,
342                                    (gpointer)&method,
343                                    (gpointer)&mechanisms))
344     {
345         if (!_gsignond_db_metadata_database_exec ( self,
346                 "INSERT OR IGNORE INTO METHODS (method) "
347                 "VALUES( %Q );",
348                 method)) {
349             DBG ("Insert methods to DB failed");
350             return FALSE;
351         }
352         /* mechanisms insert */
353         mech_iter = g_sequence_get_begin_iter (mechanisms);
354         while (!g_sequence_iter_is_end (mech_iter)) {
355             if (!_gsignond_db_metadata_database_exec (self,
356                     "INSERT OR IGNORE INTO MECHANISMS (mechanism) "
357                     "VALUES(%Q);",
358                     g_sequence_get (mech_iter))) {
359                 DBG ("Insert mechanisms to DB failed");
360                 return FALSE;
361             }
362             mech_iter = g_sequence_iter_next (mech_iter);
363         }
364     }
365
366     return TRUE;
367 }
368
369 gboolean
370 _gsignond_db_metadata_database_update_acl (
371         GSignondDbMetadataDatabase *self,
372         GSignondIdentityInfo *identity,
373         GSignondSecurityContextList *acl)
374 {
375     GSignondSecurityContextList *list = NULL;
376     GSignondSecurityContext *ctx = NULL;
377
378     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
379     g_return_val_if_fail (identity != NULL, FALSE);
380
381     if (!acl || g_list_length (acl) <= 0) {
382         DBG ("NULL acl or no acl to be added to DB");
383         return FALSE;
384     }
385
386     for (list = acl;  list != NULL; list = g_list_next (list)) {
387         ctx = (GSignondSecurityContext *) list->data;
388         _gsignond_db_metadata_database_exec (self,
389                 "INSERT OR IGNORE INTO SECCTX (sysctx, appctx) "
390                 "VALUES (%Q, %Q);",
391                 ctx->sys_ctx, ctx->app_ctx);
392     }
393     return TRUE;
394 }
395
396 gboolean
397 _gsignond_db_metadata_database_update_owner (
398         GSignondDbMetadataDatabase *self,
399         GSignondIdentityInfo *identity,
400         GSignondSecurityContext *owner)
401 {
402     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
403     g_return_val_if_fail (identity != NULL, FALSE);
404
405     if (!owner) {
406         DBG ("no owner to be added to DB");
407         return FALSE;
408     }
409
410     if (owner->sys_ctx && strlen (owner->sys_ctx) > 0) {
411         _gsignond_db_metadata_database_exec (self,
412                     "INSERT OR IGNORE INTO "
413                     "SECCTX (sysctx, appctx) "
414                     "VALUES (%Q, %Q);",
415                     owner->sys_ctx, owner->app_ctx);
416     }
417
418     return TRUE;
419 }
420
421 static void
422 _gsignond_db_metadata_database_dispose (GObject *gobject)
423 {
424     g_return_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (gobject));
425     GSignondDbMetadataDatabase *self = GSIGNOND_DB_METADATA_DATABASE (gobject);
426
427     if (self->config) {
428         g_object_unref (self->config);
429         self->config = NULL;
430     }
431
432     /* Chain up to the parent class */
433     G_OBJECT_CLASS (gsignond_db_metadata_database_parent_class)->dispose (
434             gobject);
435 }
436
437 static void
438 gsignond_db_metadata_database_class_init (
439         GSignondDbMetadataDatabaseClass *klass)
440 {
441     GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
442
443     gobject_class->set_property = _set_property;
444     gobject_class->get_property = _get_property;
445     gobject_class->dispose = _gsignond_db_metadata_database_dispose;
446
447     properties[PROP_CONFIG] = g_param_spec_object ("config",
448                                                    "config",
449                                                    "Configuration object",
450                                                    GSIGNOND_TYPE_CONFIG,
451                                                    G_PARAM_CONSTRUCT_ONLY |
452                                                    G_PARAM_READWRITE |
453                                                    G_PARAM_STATIC_STRINGS);
454     g_object_class_install_properties (gobject_class, N_PROPERTIES, properties);
455
456     GSignondDbSqlDatabaseClass *sql_class =
457             GSIGNOND_DB_SQL_DATABASE_CLASS (klass);
458
459     sql_class->create = _gsignond_db_metadata_database_create;
460     sql_class->clear = _gsignond_db_metadata_database_clear;
461
462 }
463
464 static void
465 gsignond_db_metadata_database_init (
466         GSignondDbMetadataDatabase *self)
467 {
468     self->config = NULL;
469 }
470
471 /**
472  * gsignond_db_metadata_database_new:
473  *
474  * @config: (transfer none) #GSignondConfig config data
475  *
476  * Creates new #GSignondDbMetadataDatabase object
477  *
478  * Returns : (transfer full) the #GSignondDbMetadataDatabase object
479  */
480 GSignondDbMetadataDatabase *
481 gsignond_db_metadata_database_new (GSignondConfig *config)
482 {
483     return GSIGNOND_DB_METADATA_DATABASE (
484             g_object_new (GSIGNOND_DB_TYPE_METADATA_DATABASE,
485                           "config", config, NULL));
486 }
487
488 static gboolean
489 _gsignond_db_metadata_database_open (
490         GSignondDbSqlDatabase *obj,
491         const gchar *filename,
492         int flags)
493 {
494     const gchar *dir = NULL;
495     gchar *db_filename = NULL;
496     gboolean ret = FALSE;
497     gint dir_created = 0;
498     GSignondDbMetadataDatabase *self = NULL;
499
500     self = GSIGNOND_DB_METADATA_DATABASE (obj);
501
502     g_return_val_if_fail (self, FALSE);
503
504     if (!filename || strlen (filename) <= 0) {
505         ERR ("Missing Metadata DB filename");
506         return FALSE;
507     }
508     dir = gsignond_config_get_string (self->config,
509             GSIGNOND_CONFIG_GENERAL_SECURE_DIR);
510     if (!dir) {
511         ERR ("Invalid Metadata DB directory");
512         return FALSE;
513     }
514     db_filename = g_build_filename (dir, filename, NULL);
515     if (!db_filename) {
516         ERR ("Invalid Metadata DB filename");
517         return FALSE;
518     }
519
520     dir_created = g_mkdir_with_parents (dir, S_IRWXU);
521     if (dir_created != 0) {
522         ERR ("Metadata DB directory does not exist");
523         goto _open_exit;
524     }
525
526     ret = gsignond_db_sql_database_open (obj, db_filename, flags);
527
528 _open_exit:
529     g_free (db_filename);
530     return ret;
531 }
532
533 static gboolean
534 _gsignond_db_metadata_database_create (
535         GSignondDbSqlDatabase *obj)
536 {
537     const gchar *queries = NULL;
538     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (obj), FALSE);
539     RETURN_IF_NOT_OPEN (obj, FALSE);
540     gint fk_enabled = 0;
541     gint version = 0;
542
543     queries = "PRAGMA foreign_keys = 1;";
544     if (!gsignond_db_sql_database_exec (obj, queries)) {
545         ERR ("Metadata DB enabling foreign keys failed");
546         return FALSE;
547     }
548
549     gsignond_db_sql_database_query_exec_int (obj, "PRAGMA foreign_keys;",
550             &fk_enabled);
551     if (!fk_enabled) {
552         ERR ("Metadata DB - foreign keys not enabled");
553         return FALSE;
554     }
555
556     version = gsignond_db_sql_database_get_db_version(obj,
557                 "PRAGMA user_version;");
558     if (version > 0) {
559         DBG ("Metadata DB is already created with with version (%d) and "
560                 "foreign keys enabled (%d)", version, fk_enabled);
561         return TRUE;
562     }
563
564     queries = "PRAGMA user_version = 1;";
565     if (!gsignond_db_sql_database_exec (obj, queries)) {
566         DBG ("Metadata DB setting version failed");
567         return FALSE;
568     }
569
570     version = gsignond_db_sql_database_get_db_version(obj,
571             "PRAGMA user_version;");
572     DBG ("Metadata DB is to be created with version (%d) and foreign keys "
573             "enabled(%d)", version, fk_enabled);
574
575     queries = ""
576             "CREATE TABLE IDENTITY"
577             "(id INTEGER PRIMARY KEY AUTOINCREMENT,"
578             "caption TEXT,"
579             "username TEXT,"
580             "flags INTEGER,"
581             "type INTEGER);"
582
583             "CREATE TABLE METHODS"
584             "(id INTEGER PRIMARY KEY AUTOINCREMENT,"
585             "method TEXT UNIQUE);"
586
587             "CREATE TABLE MECHANISMS"
588             "(id INTEGER PRIMARY KEY AUTOINCREMENT,"
589             "mechanism TEXT UNIQUE);"
590
591             "CREATE TABLE SECCTX"
592             "(id INTEGER PRIMARY KEY AUTOINCREMENT,"
593             "sysctx TEXT,"
594             "appctx TEXT,"
595             "CONSTRAINT tokc UNIQUE(sysctx, appctx) ON CONFLICT REPLACE);"
596
597             "CREATE INDEX sysidx ON SECCTX(sysctx);"
598             "CREATE INDEX appidx ON SECCTX(appctx);"
599
600             "CREATE TABLE REALMS"
601             "(identity_id INTEGER CONSTRAINT fk_identity_id "
602             "REFERENCES IDENTITY(id) ON DELETE CASCADE,"
603             "realm TEXT,"
604             "hostname TEXT,"
605             "PRIMARY KEY (identity_id, realm, hostname));"
606
607             "CREATE TABLE ACL"
608             "(rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
609             "identity_id INTEGER CONSTRAINT fk_identity_id REFERENCES "
610             "IDENTITY(id) ON DELETE CASCADE,"
611             "method_id INTEGER CONSTRAINT fk_method_id REFERENCES "
612             "METHODS(id),"
613             "mechanism_id INTEGER CONSTRAINT fk_mechanism_id "
614             "REFERENCES MECHANISMS(id),"
615             "secctx_id INTEGER CONSTRAINT fk_secctx_id REFERENCES "
616             "SECCTX(id));"
617
618             "CREATE TABLE REFS"
619             "(identity_id INTEGER CONSTRAINT fk_identity_id "
620             "REFERENCES IDENTITY(id) ON DELETE CASCADE,"
621             "secctx_id INTEGER CONSTRAINT fk_secctx_id REFERENCES "
622             "SECCTX(id),"
623             "ref TEXT,"
624             "PRIMARY KEY (identity_id, secctx_id, ref));"
625
626             "CREATE TABLE OWNER"
627             "(rowid INTEGER PRIMARY KEY AUTOINCREMENT,"
628             "identity_id INTEGER CONSTRAINT fk_identity_id "
629             "REFERENCES IDENTITY(id) ON DELETE CASCADE,"
630             "secctx_id INTEGER CONSTRAINT fk_secctx_id REFERENCES SECCTX(id) "
631             ");"
632
633             // Triggers for deleting orphan SECCTX entries
634             "CREATE TRIGGER fkdstale_ACL_secctx_id_SECCTX_id"
635             "BEFORE DELETE ON [ACL]"
636             "FOR EACH ROW BEGIN"
637             "    DELETE FROM SECCTX WHERE SECCTX.id = OLD.secctx_id AND "
638             "    (SELECT COUNT(*) FROM REFS WHERE "
639             "    REFS.secctx_id = OLD.secctx_id) == 0 AND "
640             "    (SELECT COUNT(*) FROM OWNER WHERE "
641             "    OWNER.secctx_id = OLD.secctx_id) == 0;"
642             "END;"
643
644             "CREATE TRIGGER fkdstale_REFS_secctx_id_SECCTX_id"
645             "BEFORE DELETE ON [REFS]"
646             "FOR EACH ROW BEGIN"
647             "    DELETE FROM SECCTX WHERE SECCTX.id = OLD.secctx_id AND "
648             "    (SELECT COUNT(*) FROM ACL WHERE "
649             "    ACL.secctx_id = OLD.secctx_id) == 0 AND "
650             "    (SELECT COUNT(*) FROM OWNER WHERE "
651             "    OWNER.secctx_id = OLD.secctx_id) == 0;"
652             "END;"
653
654             "CREATE TRIGGER fkdstale_OWNER_secctx_id_SECCTX_id"
655             "BEFORE DELETE ON [OWNER]"
656             "FOR EACH ROW BEGIN"
657             "    DELETE FROM SECCTX WHERE SECCTX.id = OLD.secctx_id AND "
658             "    (SELECT COUNT(*) FROM ACL WHERE "
659             "    ACL.secctx_id = OLD.secctx_id) == 0 AND "
660             "    (SELECT COUNT(*) FROM REFS WHERE "
661             "    REFS.secctx_id = OLD.secctx_id) == 0;"
662             "END;"
663
664 #ifdef ENABLE_DB_ACL_TRIGGERS
665             // Trigger for deleting orphan METHODS entries
666             "CREATE TRIGGER fkdstale_ACL_method_id_METHODS_id"
667             "BEFORE DELETE ON [ACL]"
668             "FOR EACH ROW BEGIN"
669             "    DELETE FROM METHODS WHERE METHODS.id = OLD.method_id AND "
670             "    (SELECT COUNT(*) FROM ACL WHERE "
671             "    ACL.method_id = OLD.method_id) == 1;"
672             "END;"
673
674             // Trigger for deleting orphan MECHANISMS entries
675             "CREATE TRIGGER fkdstale_ACL_mechanism_id_MECHANISMS_id"
676             "BEFORE DELETE ON [ACL]"
677             "FOR EACH ROW BEGIN"
678             "    DELETE FROM MECHANISMS WHERE MECHANISMS.id = OLD.mechanism_id "
679             "    AND (SELECT COUNT(*) FROM ACL WHERE "
680             "    ACL.mechanism_id = OLD.mechanism_id) == 1;"
681             "END;"
682 #endif
683
684             /*
685              * triggers generated with
686              * http://www.rcs-comp.com/site/index.php/view/Utilities-
687              * SQLite_foreign_key_trigger_generator
688              */
689             /* insert triggers to force foreign keys support */
690             // Foreign Key Preventing insert
691             "CREATE TRIGGER fki_REALMS_identity_id_IDENTITY_id"
692             "BEFORE INSERT ON [REALMS]"
693             "FOR EACH ROW BEGIN"
694             "  SELECT RAISE(ROLLBACK, 'insert on table REALMS violates foreign "
695             "key constraint fki_REALMS_identity_id_IDENTITY_id')"
696             "  WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM IDENTITY "
697             "WHERE id = NEW.identity_id) IS NULL;"
698             "END;"
699
700             // Foreign key preventing update
701             "CREATE TRIGGER fku_REALMS_identity_id_IDENTITY_id"
702             "BEFORE UPDATE ON [REALMS]"
703             "FOR EACH ROW BEGIN"
704             "    SELECT RAISE(ROLLBACK, 'update on table REALMS violates "
705             "foreign key constraint fku_REALMS_identity_id_IDENTITY_id')"
706             "      WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM "
707             "IDENTITY WHERE id = NEW.identity_id) IS NULL;"
708             "END;"
709
710             // Foreign Key Preventing insert
711             "CREATE TRIGGER fki_ACL_identity_id_IDENTITY_id"
712             "BEFORE INSERT ON [ACL]"
713             "FOR EACH ROW BEGIN"
714             "  SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign "
715             "key constraint fki_ACL_identity_id_IDENTITY_id')"
716             "  WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM IDENTITY "
717             "WHERE id = NEW.identity_id) IS NULL;"
718             "END;"
719
720             // Foreign key preventing update
721             "CREATE TRIGGER fku_ACL_identity_id_IDENTITY_id"
722             "BEFORE UPDATE ON [ACL]"
723             "FOR EACH ROW BEGIN"
724             "    SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign "
725             "key constraint fku_ACL_identity_id_IDENTITY_id')"
726             "      WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM "
727             "IDENTITY WHERE id = NEW.identity_id) IS NULL;"
728             "END;"
729
730             // Foreign Key Preventing insert
731             "CREATE TRIGGER fki_ACL_method_id_METHODS_id"
732             "BEFORE INSERT ON [ACL]"
733             "FOR EACH ROW BEGIN"
734             "  SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign "
735             "key constraint fki_ACL_method_id_METHODS_id')"
736             "  WHERE NEW.method_id IS NOT NULL AND (SELECT id FROM METHODS "
737             "WHERE id = NEW.method_id) IS NULL;"
738             "END;"
739
740             // Foreign key preventing update
741             "CREATE TRIGGER fku_ACL_method_id_METHODS_id"
742             "BEFORE UPDATE ON [ACL]"
743             "FOR EACH ROW BEGIN"
744             "    SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign "
745             "key constraint fku_ACL_method_id_METHODS_id')"
746             "      WHERE NEW.method_id IS NOT NULL AND (SELECT id FROM METHODS "
747             "WHERE id = NEW.method_id) IS NULL;"
748             "END;"
749
750             // Foreign Key Preventing insert
751             "CREATE TRIGGER fki_ACL_mechanism_id_MECHANISMS_id"
752             "BEFORE INSERT ON [ACL]"
753             "FOR EACH ROW BEGIN"
754             "  SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign "
755             "key constraint fki_ACL_mechanism_id_MECHANISMS_id')"
756             "  WHERE NEW.mechanism_id IS NOT NULL AND (SELECT id FROM "
757             "MECHANISMS WHERE id = NEW.mechanism_id) IS NULL;"
758             "END;"
759
760             // Foreign key preventing update
761             "CREATE TRIGGER fku_ACL_mechanism_id_MECHANISMS_id"
762             "BEFORE UPDATE ON [ACL]"
763             "FOR EACH ROW BEGIN"
764             "    SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign "
765             "key constraint fku_ACL_mechanism_id_MECHANISMS_id')"
766             "      WHERE NEW.mechanism_id IS NOT NULL AND (SELECT id FROM "
767             "MECHANISMS WHERE id = NEW.mechanism_id) IS NULL;"
768             "END;"
769
770             // Foreign Key Preventing insert
771             "CREATE TRIGGER fki_ACL_secctx_id_SECCTX_id"
772             "BEFORE INSERT ON [ACL]"
773             "FOR EACH ROW BEGIN"
774             "  SELECT RAISE(ROLLBACK, 'insert on table ACL violates foreign "
775             "key constraint fki_ACL_secctx_id_SECCTX_id')"
776             "  WHERE NEW.secctx_id IS NOT NULL AND (SELECT id FROM SECCTX "
777             "WHERE id = NEW.secctx_id) IS NULL;"
778             "END;"
779
780             // Foreign key preventing update
781             "CREATE TRIGGER fku_ACL_secctx_id_SECCTX_id"
782             "BEFORE UPDATE ON [ACL]"
783             "FOR EACH ROW BEGIN"
784             "    SELECT RAISE(ROLLBACK, 'update on table ACL violates foreign "
785             "key constraint fku_ACL_secctx_id_SECCTX_id')"
786             "      WHERE NEW.secctx_id IS NOT NULL AND (SELECT id FROM SECCTX "
787             "WHERE id = NEW.secctx_id) IS NULL;"
788             "END;"
789
790             // Foreign Key Preventing insert
791             "CREATE TRIGGER fki_REFS_identity_id_IDENTITY_id"
792             "BEFORE INSERT ON [REFS]"
793             "FOR EACH ROW BEGIN"
794             "  SELECT RAISE(ROLLBACK, 'insert on table REFS violates foreign "
795             "key constraint fki_REFS_identity_id_IDENTITY_id')"
796             "  WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM IDENTITY "
797             "WHERE id = NEW.identity_id) IS NULL;"
798             "END;"
799
800             // Foreign key preventing update
801             "CREATE TRIGGER fku_REFS_identity_id_IDENTITY_id"
802             "BEFORE UPDATE ON [REFS]"
803             "FOR EACH ROW BEGIN"
804             "    SELECT RAISE(ROLLBACK, 'update on table REFS violates foreign "
805             "key constraint fku_REFS_identity_id_IDENTITY_id')"
806             "      WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM "
807             "IDENTITY WHERE id = NEW.identity_id) IS NULL;"
808             "END;"
809
810             // Foreign Key Preventing insert
811             "CREATE TRIGGER fki_REFS_secctx_id_SECCTX_id"
812             "BEFORE INSERT ON [REFS]"
813             "FOR EACH ROW BEGIN"
814             "  SELECT RAISE(ROLLBACK, 'insert on table REFS violates foreign "
815             "key constraint fki_REFS_secctx_id_SECCTX_id')"
816             "  WHERE NEW.secctx_id IS NOT NULL AND (SELECT id FROM SECCTX "
817             "WHERE id = NEW.secctx_id) IS NULL;"
818             "END;"
819
820             // Foreign key preventing update
821             "CREATE TRIGGER fku_REFS_secctx_id_SECCTX_id"
822             "BEFORE UPDATE ON [REFS]"
823             "FOR EACH ROW BEGIN"
824             "    SELECT RAISE(ROLLBACK, 'update on table REFS violates foreign "
825             "key constraint fku_REFS_secctx_id_SECCTX_id')"
826             "      WHERE NEW.secctx_id IS NOT NULL AND (SELECT id FROM SECCTX "
827             "WHERE id = NEW.secctx_id) IS NULL;"
828             "END;"
829
830             // Foreign Key Preventing insert
831             "CREATE TRIGGER fki_OWNER_identity_id_IDENTITY_id"
832             "BEFORE INSERT ON [OWNER]"
833             "FOR EACH ROW BEGIN"
834             "    SELECT RAISE(ROLLBACK, 'insert on table OWNER violates "
835             "foreign key constraint fki_OWNER_identity_id_IDENTITY_id')"
836             "    WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM "
837             "IDENTITY WHERE id = NEW.identity_id) IS NULL;"
838             "END;"
839
840             // Foreign key preventing update
841             "CREATE TRIGGER fku_OWNER_identity_id_IDENTITY_id"
842             "BEFORE UPDATE ON [OWNER]"
843             "FOR EACH ROW BEGIN"
844             "    SELECT RAISE(ROLLBACK, 'update on table OWNER violates "
845             "foreign key constraint fku_OWNER_identity_id_IDENTITY_id')"
846             "    WHERE NEW.identity_id IS NOT NULL AND (SELECT id FROM "
847             "IDENTITY WHERE id = NEW.identity_id) IS NULL;"
848             "END;"
849
850             // Foreign Key Preventing insert
851             "CREATE TRIGGER fki_OWNER_secctx_id_SECCTX_id"
852             "BEFORE INSERT ON [OWNER]"
853             "FOR EACH ROW BEGIN"
854             "   SELECT RAISE(ROLLBACK, 'insert on table OWNER violates foreign "
855             "key constraint fki_OWNER_secctx_id_SECCTX_id')"
856             "   WHERE NEW.secctx_id IS NOT NULL AND (SELECT id FROM SECCTX "
857             "WHERE id = NEW.secctx_id) IS NULL;"
858             "END;"
859
860             // Foreign key preventing update
861             "CREATE TRIGGER fku_OWNER_secctx_id_SECCTX_id"
862             "BEFORE UPDATE ON [OWNER]"
863             "FOR EACH ROW BEGIN"
864             "    SELECT RAISE(ROLLBACK, 'update on table OWNER violates "
865             "foreign key constraint fku_OWNER_secctx_id_SECCTX_id')"
866             "    WHERE NEW.secctx_id IS NOT NULL AND (SELECT id FROM SECCTX "
867             "WHERE id = NEW.secctx_id) IS NULL;"
868             "END;"
869             ;
870
871     return gsignond_db_sql_database_transaction_exec (obj, queries);
872 }
873
874 static gboolean
875 _gsignond_db_metadata_database_clear (
876         GSignondDbSqlDatabase *obj)
877 {
878     const gchar *queries = NULL;
879
880     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (obj), FALSE);
881     RETURN_IF_NOT_OPEN (obj, FALSE);
882
883     queries = ""
884             "DELETE FROM IDENTITY;"
885             "DELETE FROM METHODS;"
886             "DELETE FROM MECHANISMS;"
887             "DELETE FROM ACL;"
888             "DELETE FROM REALMS;"
889             "DELETE FROM SECCTX;"
890             "DELETE FROM OWNER;";
891
892     return gsignond_db_sql_database_transaction_exec (obj, queries);
893 }
894
895 /**
896  * gsignond_db_metadata_database_open:
897  *
898  * @self: instance of #GSignondDbMetadataDatabase
899  *
900  * Opens a connection to DB.
901  *
902  * Returns: TRUE if successful, FALSE otherwise.
903  */
904 gboolean
905 gsignond_db_metadata_database_open (GSignondDbMetadataDatabase *self)
906 {
907     const gchar *filename = NULL;
908
909     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
910
911     if (gsignond_db_sql_database_is_open (GSIGNOND_DB_SQL_DATABASE (self)))
912         return TRUE;
913
914     filename = gsignond_config_get_string (self->config,
915             GSIGNOND_CONFIG_DB_METADATA_DB_FILENAME);
916
917     return _gsignond_db_metadata_database_open (
918             GSIGNOND_DB_SQL_DATABASE (self), filename,
919             SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
920 }
921
922 /**
923  * gsignond_db_metadata_database_insert_method:
924  *
925  * @self: instance of #GSignondDbMetadataDatabase
926  * @method: the method to be inserted
927  * @method_id: (transfer none) id of the method inserted
928  *
929  * Inserts the method into the db.
930  *
931  * Returns: TRUE if successful, FALSE otherwise
932  */
933 gboolean
934 gsignond_db_metadata_database_insert_method (
935         GSignondDbMetadataDatabase *self,
936         const gchar *method,
937         guint32 *method_id)
938 {
939     gchar *query = NULL;
940     gboolean ret = FALSE;
941     *method_id = 0;
942
943     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
944     g_return_val_if_fail (method != NULL, FALSE);
945     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), FALSE);
946
947     query = sqlite3_mprintf ("INSERT INTO METHODS (method) "
948                              "VALUES (%Q);",
949                              method);
950     ret = gsignond_db_sql_database_transaction_exec (
951             GSIGNOND_DB_SQL_DATABASE (self), query);
952     sqlite3_free (query);
953     if (ret) {
954         DBG ("Retrieve method id for the inserted method");
955         *method_id = gsignond_db_metadata_database_get_method_id (self, method);
956     }
957     return ret;
958 }
959
960 /**
961  * gsignond_db_metadata_database_get_method_id:
962  *
963  * @self: instance of #GSignondDbMetadataDatabase
964  * @method: the method to be fetched
965  *
966  * Fetches the id of the specified method.
967  *
968  * Returns: the method if successful, 0 otherwise
969  */
970 guint32
971 gsignond_db_metadata_database_get_method_id (
972         GSignondDbMetadataDatabase *self,
973         const gchar *method)
974 {
975     gchar *query = NULL;
976     gint method_id = 0;
977
978     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
979     g_return_val_if_fail (method != NULL, FALSE);
980     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), method_id);
981
982     query = sqlite3_mprintf ("SELECT id FROM METHODS "
983                              "WHERE method = %Q;",
984                              method);
985     gsignond_db_sql_database_query_exec_int (
986                 GSIGNOND_DB_SQL_DATABASE (self),
987                 query,
988                 &method_id);
989     sqlite3_free (query);
990
991     return (guint32) method_id;
992 }
993
994 /**
995  * gsignond_db_metadata_database_get_methods:
996  *
997  * @self: instance of #GSignondDbMetadataDatabase
998  * @identity_id: the id of the identity
999  * @sec_ctx: the security context
1000  *
1001  * Fetches the list of the methods with the specified identity id.
1002  *
1003  * Returns: (transfer full) the list if successful, NULL otherwise.
1004  * When done list should be freed with g_list_free_full (list, g_free)
1005  */
1006 GList *
1007 gsignond_db_metadata_database_get_methods (
1008         GSignondDbMetadataDatabase *self,
1009         const guint32 identity_id,
1010         GSignondSecurityContext* sec_ctx)
1011 {
1012     gchar *query = NULL;
1013     GList *methods = NULL;
1014
1015     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), NULL);
1016     g_return_val_if_fail (sec_ctx != NULL, NULL);
1017     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), NULL);
1018
1019     if (sec_ctx->sys_ctx && strlen (sec_ctx->sys_ctx) <= 0) {
1020         query = sqlite3_mprintf ("SELECT DISTINCT METHODS.method FROM "
1021                     "( ACL JOIN METHODS ON ACL.method_id = METHODS.id ) "
1022                     "WHERE ACL.identity_id = %u;",
1023                     identity_id);
1024     } else {
1025         query = sqlite3_mprintf ("SELECT DISTINCT METHODS.method FROM "
1026                 "( ACL JOIN METHODS ON ACL.method_id = METHODS.id ) "
1027                 "WHERE ACL.identity_id = %u AND ACL.secctx_id = "
1028                 "(SELECT id FROM SECCTX "
1029                 "WHERE sysctx = %Q AND appctx = %Q);",
1030                 identity_id, sec_ctx->sys_ctx, sec_ctx->app_ctx);
1031     }
1032
1033     methods = gsignond_db_sql_database_query_exec_string_list (
1034                     GSIGNOND_DB_SQL_DATABASE (self),
1035                     query);
1036     sqlite3_free (query);
1037
1038     return methods;
1039 }
1040
1041 /**
1042  * gsignond_db_metadata_database_update_identity:
1043  *
1044  * @self: instance of #GSignondDbMetadataDatabase
1045  * @identity: the identity #GSignondIdentityInfo object
1046  *
1047  * Updates the database with the data in the identity.
1048  *
1049  * Returns: the id of the identity if successful, 0 otherwise
1050  */
1051 guint32
1052 gsignond_db_metadata_database_update_identity (
1053         GSignondDbMetadataDatabase *self,
1054         GSignondIdentityInfo *identity)
1055 {
1056     GSignondDbSqlDatabase *sql = NULL;
1057     guint32 id = 0;
1058     guint32 ret = 0;
1059     GHashTable *methods = NULL;
1060     GSequence *realms = NULL;
1061     GSignondSecurityContextList *acl = NULL, *list = NULL;
1062     GSignondSecurityContext *owner = NULL;
1063     GHashTableIter method_iter;
1064     const gchar *method = NULL;
1065     GSequence *mechanisms = NULL;
1066
1067     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), 0);
1068     g_return_val_if_fail (identity != NULL, 0);
1069     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), id);
1070
1071     sql = GSIGNOND_DB_SQL_DATABASE (self);
1072     if (!gsignond_db_sql_database_start_transaction (sql)) {
1073         return 0;
1074     }
1075
1076     /* credentials */
1077     id = _gsignond_db_metadata_database_update_credentials (self, identity);
1078     if (id == 0) {
1079         DBG ("Update credentials failed");
1080         gsignond_db_sql_database_rollback_transaction (sql);
1081         return 0;
1082     }
1083
1084     if (!gsignond_identity_info_get_is_identity_new (identity)) {
1085         DBG ("Remove old acl and owner list as identity is not new");
1086         /* remove acl */
1087         _gsignond_db_metadata_database_exec (self,
1088                 "DELETE FROM ACL WHERE identity_id = %u;", id);
1089
1090         /* remove owner */
1091         _gsignond_db_metadata_database_exec (self,
1092                 "DELETE FROM OWNER WHERE identity_id = %u;", id);
1093     }
1094
1095     /* methods */
1096     methods = gsignond_identity_info_get_methods (identity);
1097     if (!_gsignond_db_metadata_database_insert_methods (self, identity,
1098             methods)) {
1099         DBG ("Update methods failed");
1100     }
1101
1102     /* realms */
1103     realms = gsignond_identity_info_get_realms (identity);
1104     if (!_gsignond_db_metadata_database_update_realms (self,
1105             identity, id, realms)) {
1106         DBG ("Update realms failed");
1107         gsignond_db_sql_database_rollback_transaction (sql);
1108         goto finished;
1109     }
1110
1111     /* acl */
1112     acl = gsignond_identity_info_get_access_control_list (identity);
1113     if (!_gsignond_db_metadata_database_update_acl (self, identity, acl)) {
1114         DBG ("Update acl failed");
1115         gsignond_db_sql_database_rollback_transaction (sql);
1116         goto finished;
1117     }
1118
1119     /* owner */
1120     owner = gsignond_identity_info_get_owner (identity);
1121     if (!_gsignond_db_metadata_database_update_owner (self, identity, owner)){
1122         DBG ("Update owner failed");
1123         gsignond_db_sql_database_rollback_transaction (sql);
1124         goto finished;
1125     }
1126
1127
1128     /* ACL insert, this will do basically identity level ACL */
1129     g_hash_table_iter_init (&method_iter, methods);
1130     while (g_hash_table_iter_next (&method_iter, (gpointer)&method,
1131             (gpointer)&mechanisms)) {
1132
1133         if (g_list_length (acl) > 0) {
1134             for (list = acl;  list != NULL; list = g_list_next (list)) {
1135                 GSequenceIter *mech_iter = NULL;
1136                 GSignondSecurityContext *ctx = NULL;
1137
1138                 ctx = (GSignondSecurityContext *) list->data;
1139                 mech_iter = g_sequence_get_begin_iter (mechanisms);
1140                 while (!g_sequence_iter_is_end (mech_iter)) {
1141                     _gsignond_db_metadata_database_exec (self,
1142                             "INSERT OR REPLACE INTO ACL "
1143                             "(identity_id, method_id, mechanism_id, secctx_id) "
1144                             "VALUES ( %u, "
1145                             "( SELECT id FROM METHODS WHERE method = %Q ),"
1146                             "( SELECT id FROM MECHANISMS WHERE mechanism= %Q ),"
1147                             " ( SELECT id FROM SECCTX WHERE sysctx = %Q "
1148                             "AND appctx = %Q));",
1149                             id, method, g_sequence_get (mech_iter),
1150                             ctx->sys_ctx, ctx->app_ctx);
1151                     mech_iter = g_sequence_iter_next (mech_iter);
1152                 }
1153                 if (g_sequence_get_length (mechanisms) <= 0) {
1154                     _gsignond_db_metadata_database_exec (self,
1155                             "INSERT OR REPLACE INTO ACL "
1156                             "(identity_id, method_id, secctx_id) "
1157                             "VALUES ( %u, "
1158                             "( SELECT id FROM METHODS WHERE method = %Q),"
1159                             "( SELECT id FROM SECCTX WHERE sysctx = %Q AND "
1160                             "appctx = %Q ));",
1161                             id, method, ctx->sys_ctx, ctx->app_ctx);
1162                 }
1163             }
1164
1165         } else {
1166             GSequenceIter *mech_iter = NULL;
1167             mech_iter = g_sequence_get_begin_iter (mechanisms);
1168             while (!g_sequence_iter_is_end (mech_iter)) {
1169                 _gsignond_db_metadata_database_exec (self,
1170                         "INSERT OR REPLACE INTO ACL "
1171                         "(identity_id, method_id, mechanism_id) "
1172                         "VALUES ( %u, "
1173                         "( SELECT id FROM METHODS WHERE method = %Q ),"
1174                         "( SELECT id FROM MECHANISMS WHERE mechanism= %Q ));",
1175                         id, method, g_sequence_get (mech_iter));
1176                 mech_iter = g_sequence_iter_next (mech_iter);
1177             }
1178             if (g_sequence_get_length (mechanisms) <= 0) {
1179                 _gsignond_db_metadata_database_exec (self,
1180                         "INSERT OR REPLACE INTO ACL (identity_id, method_id) "
1181                         "VALUES ( %u, "
1182                         "( SELECT id FROM METHODS WHERE method = %Q ));",
1183                         id, method );
1184             }
1185         }
1186     }
1187     /* insert acl in case where methods are missing */
1188     if (g_hash_table_size (methods) <= 0) {
1189         for (list = acl;  list != NULL; list = g_list_next (list)) {
1190             GSignondSecurityContext *ctx = NULL;
1191
1192             ctx = (GSignondSecurityContext *) list->data;
1193             _gsignond_db_metadata_database_exec (self,
1194                     "INSERT OR REPLACE INTO ACL "
1195                     "(identity_id, secctx_id) "
1196                     "VALUES ( %u, "
1197                     "( SELECT id FROM SECCTX WHERE sysctx = %Q AND "
1198                     "appctx = %Q));",
1199                     id, ctx->sys_ctx, ctx->app_ctx);
1200         }
1201     }
1202
1203     /* insert owner */
1204     _gsignond_db_metadata_database_exec (self,
1205                 "INSERT OR REPLACE INTO OWNER "
1206                 "(identity_id, secctx_id) "
1207                 "VALUES ( %u, "
1208                 "( SELECT id FROM SECCTX WHERE sysctx = %Q AND appctx = %Q ));",
1209                 id, owner->sys_ctx, owner->app_ctx);
1210
1211     if (gsignond_db_sql_database_commit_transaction (sql)) {
1212         DBG ("Identity updated");
1213         ret = id;
1214     }
1215
1216 finished:
1217     if (methods) g_hash_table_unref (methods);
1218     if (realms) g_sequence_free (realms);
1219     if (acl) gsignond_security_context_list_free (acl);
1220     if (owner) gsignond_security_context_free (owner);
1221
1222     return ret;
1223 }
1224
1225 /**
1226  * gsignond_db_metadata_database_update_identity:
1227  *
1228  * @self: instance of #GSignondDbMetadataDatabase
1229  * @identity_id: the id of the identity
1230  *
1231  * Reads the identity data from the database based on the given id.
1232  *
1233  * Returns: (transfer full) the #GSignondIdentityInfo identity if successful,
1234  * NULL otherwise.
1235  */
1236 GSignondIdentityInfo *
1237 gsignond_db_metadata_database_get_identity (
1238         GSignondDbMetadataDatabase *self,
1239         const guint32 identity_id)
1240 {
1241     GSignondIdentityInfo *identity = NULL;
1242     gchar *query = NULL;
1243     gint rows = 0;
1244     GSequence *realms = NULL, *mechanisms = NULL;
1245     GHashTable *methods = NULL, *tuples = NULL;
1246     GHashTableIter iter;
1247     gchar *method = NULL;
1248     gint method_id = 0;
1249     GSignondSecurityContextList *acl = NULL;
1250     GSignondSecurityContext *owner = NULL;
1251
1252     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), NULL);
1253     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), NULL);
1254
1255     identity = gsignond_identity_info_new ();
1256     query = sqlite3_mprintf ("SELECT caption, username, flags, type "
1257                              "FROM IDENTITY WHERE id = %u;",
1258                              identity_id);
1259     rows = gsignond_db_sql_database_query_exec (GSIGNOND_DB_SQL_DATABASE (self),
1260             query, (GSignondDbSqlDatabaseQueryCallback)
1261             _gsignond_db_metadata_database_read_identity,
1262             identity);
1263     sqlite3_free (query);
1264     if (G_UNLIKELY (rows <= 0)) {
1265         DBG ("Fetch IDENTITY failed");
1266         gsignond_identity_info_unref (identity);
1267         return NULL;
1268     }
1269     gsignond_identity_info_set_id (identity, identity_id);
1270
1271     /*realms*/
1272     realms = _gsignond_db_metadata_database_get_sequence (self,
1273             "SELECT realm FROM REALMS "
1274             "WHERE identity_id = %u;",
1275             identity_id);
1276     if (realms) {
1277         gsignond_identity_info_set_realms (identity, realms);
1278         g_sequence_free (realms);
1279     }
1280
1281     /*acl*/
1282     acl = gsignond_db_metadata_database_get_accesscontrol_list (self,
1283             identity_id);
1284     if (acl) {
1285         gsignond_identity_info_set_access_control_list (identity, acl);
1286         gsignond_security_context_list_free (acl);
1287     }
1288
1289     /*owner*/
1290     owner = gsignond_db_metadata_database_get_owner (self,
1291             identity_id);
1292     if (owner) {
1293         gsignond_identity_info_set_owner (identity, owner);
1294         gsignond_security_context_free (owner);
1295     }
1296
1297     /*methods*/
1298     query = sqlite3_mprintf ("SELECT DISTINCT ACL.method_id, METHODS.method "
1299             "FROM ( ACL JOIN METHODS ON ACL.method_id = METHODS.id ) "
1300             "WHERE ACL.identity_id = %u;",
1301             identity_id);
1302     tuples = gsignond_db_sql_database_query_exec_int_string_tuple (
1303                     GSIGNOND_DB_SQL_DATABASE (self),
1304                     query);
1305     sqlite3_free (query);
1306
1307     if (tuples) {
1308         methods = g_hash_table_new_full ((GHashFunc)g_str_hash,
1309                 (GEqualFunc)g_str_equal,
1310                 (GDestroyNotify)g_free,
1311                 (GDestroyNotify)g_sequence_free);
1312         g_hash_table_iter_init(&iter, tuples);
1313         while (g_hash_table_iter_next (&iter, (gpointer *)&method_id,
1314                 (gpointer *)&method)) {
1315             /*mechanisms*/
1316             mechanisms = _gsignond_db_metadata_database_get_sequence (self,
1317                     "SELECT DISTINCT MECHANISMS.mechanism FROM "
1318                     "( MECHANISMS JOIN ACL ON ACL.mechanism_id = MECHANISMS.id ) "
1319                     "WHERE ACL.method_id = %u AND ACL.identity_id = %u;",
1320                     method_id, identity_id);
1321             g_hash_table_insert(methods, g_strdup(method), mechanisms);
1322         }
1323         g_hash_table_destroy (tuples);
1324         gsignond_identity_info_set_methods (identity, methods);
1325         g_hash_table_destroy (methods);
1326     }
1327
1328     return identity;
1329 }
1330
1331 /**
1332  * gsignond_db_metadata_database_get_identities:
1333  *
1334  * @self: instance of #GSignondDbMetadataDatabase
1335  * @filter: (transfer none) filter to apply (supported filters: Owner, Type & Caption)
1336  *
1337  * Reads all the identities that are matched by applying @filter,
1338  * from the database into a list.
1339  *
1340  * Returns: (transfer full) the list #GSignondIdentityInfoList if successful,
1341  * NULL otherwise. When done the list should be freed with
1342  * gsignond_identity_info_list_free
1343  */
1344 GSignondIdentityInfoList *
1345 gsignond_db_metadata_database_get_identities (
1346         GSignondDbMetadataDatabase *self,
1347         GSignondDictionary *filter)
1348 {
1349     GSignondIdentityInfoList *identities = NULL;
1350     gchar *owner_query = NULL;
1351     gchar *caption_query = NULL;
1352     gchar *type_query = NULL;
1353     gchar *query = NULL;
1354     GArray *ids = NULL;
1355     gint i;
1356
1357     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
1358     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), NULL);
1359
1360     if (filter) {
1361         GVariant *owner_var = NULL;
1362         const gchar *caption = NULL;
1363         gint type = 0;
1364         gboolean append_where = TRUE;
1365
1366         if ((owner_var = gsignond_dictionary_get (filter, "Owner"))) {
1367                 GSignondSecurityContext *owner_ctx =
1368                          gsignond_security_context_from_variant(owner_var);
1369                 owner_query = sqlite3_mprintf ("WHERE id IN "
1370                         "(SELECT identity_id FROM owner WHERE secctx_id = "
1371                         "(SELECT id FROM secctx WHERE sysctx=%Q AND appctx=%Q))",
1372                         gsignond_security_context_get_system_context(owner_ctx),
1373                         gsignond_security_context_get_application_context(owner_ctx));
1374                 gsignond_security_context_free (owner_ctx);
1375                 append_where = FALSE;
1376         }
1377
1378         if ((caption = gsignond_dictionary_get_string (filter, "Caption"))) {
1379                 caption_query = sqlite3_mprintf (" %s caption like '%s%%'",
1380                                              append_where ? "WHERE" : "AND", caption);
1381                 append_where = FALSE;
1382         }
1383
1384         if (gsignond_dictionary_get_int32 (filter, "Type", &type)) {
1385                 type_query = sqlite3_mprintf (" %s type = %d",
1386                                 append_where ? "WHERE" : "AND", type);
1387                 append_where = FALSE;
1388         }
1389     }
1390
1391     query = sqlite3_mprintf ("SELECT id FROM IDENTITY %s%s%s ORDER BY id",
1392                 owner_query ? owner_query : "",
1393                 caption_query ? caption_query : "",
1394                 type_query ? type_query : "");
1395     sqlite3_free(owner_query);
1396     sqlite3_free(caption_query);
1397     sqlite3_free(type_query);
1398
1399     ids = gsignond_db_sql_database_query_exec_int_array (
1400                 GSIGNOND_DB_SQL_DATABASE (self),
1401                 query);
1402     sqlite3_free (query);
1403     if (!ids) {
1404         DBG ("No identity found");
1405         return NULL;
1406     }
1407
1408     for (i=0; i < ids->len; i++) {
1409         GSignondIdentityInfo *identity = NULL;
1410         identity = gsignond_db_metadata_database_get_identity (self,
1411                 g_array_index (ids, gint, i));
1412         if (identity) {
1413             identities = g_list_append (identities, identity);
1414         }
1415     }
1416     g_array_free (ids, TRUE);
1417     return identities;
1418 }
1419
1420 /**
1421  * gsignond_db_metadata_database_remove_identity:
1422  *
1423  * @self: instance of #GSignondDbMetadataDatabase
1424  * @identity_id: the id of the identity
1425  *
1426  * Removes the identity data from the database based on the given id.
1427  *
1428  * Returns: TRUE if successful,FALSE otherwise.
1429  */
1430 gboolean
1431 gsignond_db_metadata_database_remove_identity (
1432         GSignondDbMetadataDatabase *self,
1433         const guint32 identity_id)
1434 {
1435     gchar *queries = NULL;
1436     gboolean ret = FALSE;
1437
1438     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
1439     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), FALSE);
1440
1441     /* Triggers should handle the cleanup of other tables */
1442     queries = sqlite3_mprintf ("DELETE FROM IDENTITY WHERE id = %u;",
1443                                identity_id);
1444     ret = gsignond_db_sql_database_transaction_exec (
1445             GSIGNOND_DB_SQL_DATABASE (self), queries);
1446     sqlite3_free (queries);
1447
1448     return ret;
1449 }
1450
1451 /**
1452  * gsignond_db_metadata_database_insert_reference:
1453  *
1454  * @self: instance of #GSignondDbMetadataDatabase
1455  * @identity_id: the id of the identity
1456  * @ref_owner: the owner security context
1457  * @reference: reference for the given identity
1458  *
1459  * Insert reference into the database for the given identity id.
1460  *
1461  * Returns: TRUE if successful,FALSE otherwise.
1462  */
1463 gboolean
1464 gsignond_db_metadata_database_insert_reference (
1465         GSignondDbMetadataDatabase *self,
1466         const guint32 identity_id,
1467         const GSignondSecurityContext *ref_owner,
1468         const gchar *reference)
1469 {
1470     GSignondDbSqlDatabase *sql = NULL;
1471
1472     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), 0);
1473     g_return_val_if_fail (ref_owner != NULL && reference != NULL, FALSE);
1474     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), FALSE);
1475
1476     sql = GSIGNOND_DB_SQL_DATABASE (self);
1477     if (!gsignond_db_sql_database_start_transaction (sql)) {
1478         DBG ("Start transaction failed");
1479         return FALSE;
1480     }
1481
1482     if (!_gsignond_db_metadata_database_exec (self,
1483             "INSERT OR IGNORE INTO SECCTX (sysctx, appctx) "
1484             "VALUES ( %Q, %Q );", ref_owner->sys_ctx, ref_owner->app_ctx)) {
1485         DBG ("Insertion SECCTX to DB failed");
1486         gsignond_db_sql_database_rollback_transaction (sql);
1487         return FALSE;
1488     }
1489     if (!_gsignond_db_metadata_database_exec (self,
1490             "INSERT OR REPLACE INTO REFS "
1491             "(identity_id, secctx_id, ref) "
1492             "VALUES ( %u, "
1493             "( SELECT id FROM SECCTX "
1494             "WHERE sysctx = %Q AND appctx = %Q), %Q );",
1495             identity_id, ref_owner->sys_ctx, ref_owner->app_ctx, reference)) {
1496         DBG ("Insertion to REFS failed");
1497         gsignond_db_sql_database_rollback_transaction (sql);
1498         return FALSE;
1499     }
1500
1501     return gsignond_db_sql_database_commit_transaction (sql);
1502 }
1503
1504 /**
1505  * gsignond_db_metadata_database_remove_reference:
1506  *
1507  * @self: instance of #GSignondDbMetadataDatabase
1508  * @identity_id: the id of the identity
1509  * @ref_owner: the owner security context
1510  * @reference: reference for the given identity
1511  *
1512  * Removes reference from the database for the given identity id.
1513  *
1514  * Returns: TRUE if successful,FALSE otherwise.
1515  */
1516 gboolean
1517 gsignond_db_metadata_database_remove_reference (
1518         GSignondDbMetadataDatabase *self,
1519         const guint32 identity_id,
1520         const GSignondSecurityContext *ref_owner,
1521         const gchar *reference)
1522 {
1523     GSignondDbSqlDatabase *sql = NULL;
1524     GList *refs = NULL;
1525     gboolean ret = TRUE;
1526     guint len = 0;
1527
1528     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), 0);
1529     g_return_val_if_fail (ref_owner != NULL, FALSE);
1530     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), FALSE);
1531
1532     sql = GSIGNOND_DB_SQL_DATABASE (self);
1533     if (!gsignond_db_sql_database_start_transaction (sql)) {
1534         DBG ("Start transaction failed");
1535         return FALSE;
1536     }
1537
1538     refs = gsignond_db_metadata_database_get_references (self,
1539             identity_id, ref_owner);
1540
1541     len = g_list_length (refs);
1542     if (reference && !g_list_find_custom (refs, reference,
1543                 (GCompareFunc)g_strcmp0))
1544         ret = FALSE;
1545     g_list_free_full (refs, (GDestroyNotify)g_free);
1546     if (len <= 0 || !ret) {
1547         DBG ("No ref found");
1548         gsignond_db_sql_database_rollback_transaction (sql);
1549         return FALSE;
1550     }
1551
1552     if (!reference || strlen (reference) <= 0) {
1553         ret = _gsignond_db_metadata_database_exec (self,
1554                 "DELETE FROM REFS "
1555                 "WHERE identity_id = %u AND "
1556                 "secctx_id = ( SELECT id FROM SECCTX "
1557                 "WHERE sysctx = %Q AND appctx = %Q );",
1558                 identity_id, ref_owner->sys_ctx, ref_owner->app_ctx);
1559     } else {
1560         ret = _gsignond_db_metadata_database_exec (self,
1561                 "DELETE FROM REFS "
1562                 "WHERE identity_id = %u AND "
1563                 "secctx_id = ( SELECT id FROM SECCTX "
1564                 "WHERE sysctx = %Q AND appctx = %Q ) "
1565                 "AND ref = :ref;",
1566                 identity_id, ref_owner->sys_ctx, ref_owner->app_ctx, reference);
1567     }
1568     if (!ret) {
1569         DBG ("Delete refs from DB failed");
1570         gsignond_db_sql_database_rollback_transaction (sql);
1571         return FALSE;
1572     }
1573
1574     return gsignond_db_sql_database_commit_transaction (sql);
1575 }
1576
1577 /**
1578  * gsignond_db_metadata_database_get_references:
1579  *
1580  * @self: instance of #GSignondDbMetadataDatabase
1581  * @identity_id: the id of the identity
1582  * @ref_owner: the owner security context
1583  *
1584  * Gets references from the database for the given identity id.
1585  *
1586  * Returns: (transfer full) the list #GList if successful,
1587  * NULL otherwise. When done the list should be freed with
1588  * g_list_free_full (list, g_free)
1589  */
1590 GList *
1591 gsignond_db_metadata_database_get_references (
1592         GSignondDbMetadataDatabase *self,
1593         const guint32 identity_id,
1594         const GSignondSecurityContext* ref_owner)
1595 {
1596     gchar *query = NULL;
1597     GList *list = NULL;
1598
1599     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), NULL);
1600     g_return_val_if_fail (ref_owner != NULL, NULL);
1601     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), NULL);
1602
1603     if (!ref_owner->sys_ctx || strlen (ref_owner->sys_ctx) <= 0) {
1604         query = sqlite3_mprintf ("SELECT ref FROM REFS "
1605                                  "WHERE identity_id = %u;",
1606                                  identity_id);
1607     } else {
1608         query = sqlite3_mprintf ("SELECT ref FROM REFS "
1609                 "WHERE identity_id = %u AND "
1610                 "secctx_id = (SELECT id FROM SECCTX "
1611                 "WHERE sysctx = %Q AND appctx = %Q );",
1612                 identity_id, ref_owner->sys_ctx, ref_owner->app_ctx );
1613     }
1614     list = gsignond_db_sql_database_query_exec_string_list (
1615             GSIGNOND_DB_SQL_DATABASE (self),
1616             query);
1617     sqlite3_free (query);
1618     return list;
1619 }
1620
1621 /**
1622  * gsignond_db_metadata_database_get_accesscontrol_list:
1623  *
1624  * @self: instance of #GSignondDbMetadataDatabase
1625  * @identity_id: the id of the identity whose access control list is needed
1626  *
1627  * Gets all the access control list from the database into a list.
1628  *
1629  * Returns: (transfer full) the list #GSignondSecurityContextList if successful,
1630  * NULL otherwise. When done the list should be freed with
1631  * gsignond_identity_info_list_free
1632  */
1633 GSignondSecurityContextList *
1634 gsignond_db_metadata_database_get_accesscontrol_list(
1635         GSignondDbMetadataDatabase *self,
1636         const guint32 identity_id)
1637 {
1638     GSignondSecurityContextList *list = NULL;
1639     GHashTable *tuples = NULL;
1640     gchar *query = NULL;
1641     GHashTableIter iter;
1642     const gchar *sysctx = NULL, *appctx = NULL;
1643     GSignondSecurityContext *ctx = NULL;
1644
1645     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
1646     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), NULL);
1647
1648     query = sqlite3_mprintf ("SELECT sysctx, appctx FROM SECCTX "
1649             "WHERE id IN "
1650             "(SELECT secctx_id FROM ACL WHERE identity_id = %u);",
1651             identity_id);
1652     tuples = gsignond_db_sql_database_query_exec_string_tuple (
1653                     GSIGNOND_DB_SQL_DATABASE (self),
1654                     query);
1655     sqlite3_free (query);
1656
1657     if (tuples) {
1658         g_hash_table_iter_init(&iter, tuples);
1659         while (g_hash_table_iter_next (&iter, (gpointer *)&sysctx,
1660                 (gpointer *)&appctx)) {
1661             ctx = gsignond_security_context_new_from_values (sysctx, appctx);
1662             list = g_list_append (list, ctx);
1663         }
1664         g_hash_table_unref (tuples);
1665     }
1666     return list;
1667 }
1668
1669 /**
1670  * gsignond_db_metadata_database_get_owner:
1671  *
1672  * @self: instance of #GSignondDbMetadataDatabase
1673  * @identity_id: the id of the identity whose owner list is needed
1674  *
1675  * Gets the onwer of identity referred by @identity_id from the database.
1676  *
1677  * Returns: (transfer full) the  #GSignondSecurityContext if successful,
1678  * NULL otherwise. When done the list should be freed with
1679  * gsignond_identity_info_unref
1680  */
1681 GSignondSecurityContext *
1682 gsignond_db_metadata_database_get_owner(
1683         GSignondDbMetadataDatabase *self,
1684         const guint32 identity_id)
1685 {
1686     GHashTable *tuples = NULL;
1687     gchar *query = NULL;
1688     GSignondSecurityContext *ctx = NULL;
1689
1690     g_return_val_if_fail (GSIGNOND_DB_IS_METADATA_DATABASE (self), FALSE);
1691     RETURN_IF_NOT_OPEN (GSIGNOND_DB_SQL_DATABASE (self), NULL);
1692
1693     query = sqlite3_mprintf ("SELECT sysctx, appctx FROM SECCTX "
1694             "WHERE id IN "
1695             "(SELECT secctx_id FROM OWNER WHERE identity_id = %u);",
1696             identity_id);
1697     tuples = gsignond_db_sql_database_query_exec_string_tuple (
1698                     GSIGNOND_DB_SQL_DATABASE (self),
1699                     query);
1700     sqlite3_free (query);
1701
1702     if (tuples) {
1703         GHashTableIter iter;
1704         const gchar *sysctx = NULL, *appctx = NULL;
1705         g_hash_table_iter_init(&iter, tuples);
1706         while (g_hash_table_iter_next (&iter, (gpointer *)&sysctx,
1707                 (gpointer *)&appctx)) {
1708             ctx = gsignond_security_context_new_from_values (sysctx, appctx);
1709             break;
1710         }
1711         g_hash_table_unref (tuples);
1712     }
1713     return ctx;
1714 }
1715
1716