XLIB = -lgcov
endif
+if HAVE_SQLITE
+SQLITE_PLUGIN = libgnunet_plugin_identity_provider_sqlite.la
+endif
+
pkgcfgdir= $(pkgdatadir)/config.d/
libexecdir= $(pkglibdir)/libexec/
libgnunetidentityprovider.la
plugin_LTLIBRARIES = \
libgnunet_plugin_rest_identity_provider.la \
- libgnunet_plugin_gnsrecord_identity_provider.la
+ libgnunet_plugin_gnsrecord_identity_provider.la \
+ $(SQLITE_PLUGIN)
bin_PROGRAMS = \
gnunet-identity-token \
libgnunet_plugin_gnsrecord_identity_provider_la_LDFLAGS = \
$(GN_PLUGIN_LDFLAGS)
+libgnunet_plugin_identity_provider_sqlite_la_SOURCES = \
+ plugin_identity_provider_sqlite.c
+libgnunet_plugin_identity_provider_sqlite_la_LIBADD = \
+ $(top_builddir)/src/identity-provider/libgnunetidentityprovider.la \
+ $(top_builddir)/src/sq/libgnunetsq.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
+ $(LTLIBINTL)
+libgnunet_plugin_identity_provider_sqlite_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+
gnunet_service_identity_provider_SOURCES = \
gnunet-service-identity-provider.c \
#include "gnunet_credential_service.h"
#include "gnunet_statistics_service.h"
#include "gnunet_gns_service.h"
+#include "gnunet_identity_provider_plugin.h"
#include "gnunet_signatures.h"
#include "identity_provider.h"
#include "identity_token.h"
*/
static struct GNUNET_IDENTITY_Handle *identity_handle;
+/**
+ * Database handle
+ */
+static struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *TKT_database;
+
+/**
+ * Name of DB plugin
+ */
+static char *db_lib_name;
+
/**
* Token expiration interval
*/
*/
struct IdpClient;
+/**
+ * A ticket iteration operation.
+ */
+struct TicketIteration
+{
+ /**
+ * DLL
+ */
+ struct TicketIteration *next;
+
+ /**
+ * DLL
+ */
+ struct TicketIteration *prev;
+
+ /**
+ * Client which intiated this zone iteration
+ */
+ struct IdpClient *client;
+
+ /**
+ * Key of the identity we are iterating over.
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey identity;
+
+ /**
+ * Identity is audience
+ */
+ uint32_t is_audience;
+
+ /**
+ * The operation id fot the iteration in the response for the client
+ */
+ uint32_t r_id;
+
+ /**
+ * Offset of the iteration used to address next result of the
+ * iteration in the store
+ *
+ * Initialy set to 0 in handle_iteration_start
+ * Incremented with by every call to handle_iteration_next
+ */
+ uint32_t offset;
+
+};
+
+
+
/**
* Callback after an ABE bootstrap
*
* in progress initiated by this client
*/
struct AttributeIterator *op_tail;
+
+ /**
+ * Head of DLL of ticket iteration ops
+ */
+ struct TicketIteration *ticket_iter_head;
+
+ /**
+ * Tail of DLL of ticket iteration ops
+ */
+ struct TicketIteration *ticket_iter_tail;
};
GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
stats = NULL;
}
-
+ GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name,
+ TKT_database));
+ GNUNET_free (db_lib_name);
+ db_lib_name = NULL;
if (NULL != timeout_task)
GNUNET_SCHEDULER_cancel (timeout_task);
if (NULL != update_task)
static void
cleanup_ticket_issue_handle (struct TicketIssueHandle *handle)
{
- struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *le;
- struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *tmp_le;
-
- for (le = handle->attrs->list_head; NULL != le;)
- {
- GNUNET_free (le->attribute);
- tmp_le = le;
- le = le->next;
- GNUNET_free (tmp_le);
- }
- GNUNET_free (handle->attrs);
+ if (NULL != handle->attrs)
+ attribute_list_destroy (handle->attrs);
if (NULL != handle->ns_qe)
GNUNET_NAMESTORE_cancel (handle->ns_qe);
GNUNET_free (handle);
}
+
+static void
+send_ticket_result (struct IdpClient *client,
+ uint32_t r_id,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
+ const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs)
+{
+ struct TicketResultMessage *irm;
+ struct GNUNET_MQ_Envelope *env;
+ size_t attrs_size;
+ struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket_buf;
+ char *attrs_buf;
+
+ attrs_size = attribute_list_serialize_get_size (attrs);
+
+ env = GNUNET_MQ_msg_extra (irm,
+ sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket2) + attrs_size,
+ GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT);
+ ticket_buf = (struct GNUNET_IDENTITY_PROVIDER_Ticket2 *)&irm[1];
+ *ticket_buf = *ticket;
+ attrs_buf = (char*)&ticket_buf[1];
+ attribute_list_serialize (attrs,
+ attrs_buf);
+ irm->id = htonl (r_id);
+
+ GNUNET_MQ_send (client->mq,
+ env);
+}
+
static void
store_ticket_issue_cont (void *cls,
int32_t success,
const char *emsg)
{
- struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket;
struct TicketIssueHandle *handle = cls;
- struct TicketResultMessage *irm;
- struct GNUNET_MQ_Envelope *env;
handle->ns_qe = NULL;
if (GNUNET_SYSERR == success)
GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
return;
}
- env = GNUNET_MQ_msg_extra (irm,
- sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket2),
- GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT);
- ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket2 *)&irm[1];
- *ticket = handle->ticket;
- irm->id = handle->r_id;
-
- GNUNET_MQ_send (handle->client->mq,
- env);
+ send_ticket_result (handle->client,
+ handle->r_id,
+ &handle->ticket,
+ handle->attrs);
cleanup_ticket_issue_handle (handle);
}
int
serialize_abe_keyinfo2 (const struct TicketIssueHandle *handle,
- const struct GNUNET_CRYPTO_AbeKey *rp_key,
- struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
- char **result)
+ const struct GNUNET_CRYPTO_AbeKey *rp_key,
+ struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
+ char **result)
{
struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *le;
char *write_ptr;
char attrs_str_len;
ssize_t size;
-
+
struct GNUNET_CRYPTO_SymmetricSessionKey skey;
struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
struct GNUNET_HashCode new_key_hash;
ssize_t enc_size;
-
+
size = GNUNET_CRYPTO_cpabe_serialize_key (rp_key,
(void**)&serialized_key);
attrs_str_len = 0;
ih = GNUNET_new (struct TicketIssueHandle);
attrs_len = ntohs (im->attr_len);
ih->attrs = attribute_list_deserialize ((char*)&im[1], attrs_len);
- ih->r_id = im->id;
+ ih->r_id = ntohl (im->id);
ih->client = idp;
ih->identity = im->identity;
GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity,
GNUNET_SERVICE_client_continue (idp->client);
}
+/**
+ * Ticket iteration processor result
+ */
+enum ZoneIterationResult
+{
+ /**
+ * Iteration start.
+ */
+ IT_START = 0,
+
+ /**
+ * Found tickets,
+ * Continue to iterate with next iteration_next call
+ */
+ IT_SUCCESS_MORE_AVAILABLE = 1,
+
+ /**
+ * Iteration complete
+ */
+ IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2
+};
+
+
+/**
+ * Context for ticket iteration
+ */
+struct TicketIterationProcResult
+{
+ /**
+ * The ticket iteration handle
+ */
+ struct TicketIteration *ti;
+
+ /**
+ * Iteration result: iteration done?
+ * #IT_SUCCESS_MORE_AVAILABLE: if there may be more results overall but
+ * we got one for now and have sent it to the client
+ * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
+ * #IT_START: if we are still trying to find a result.
+ */
+ int res_iteration_finished;
+
+};
+
+
+
+/**
+ * Process ticket from database
+ *
+ * @param cls struct TicketIterationProcResult
+ * @param ticket the ticket
+ * @param attrs the attributes
+ */
+static void
+ticket_iterate_proc (void *cls,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
+ const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs)
+{
+ struct TicketIterationProcResult *proc = cls;
+
+ if (NULL == ticket)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Iteration done\n");
+ proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
+ return;
+ }
+ if ((NULL == ticket) || (NULL == attrs))
+ {
+ /* error */
+ proc->res_iteration_finished = IT_START;
+ GNUNET_break (0);
+ return;
+ }
+ proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
+ send_ticket_result (proc->ti->client,
+ proc->ti->r_id,
+ ticket,
+ attrs);
+
+}
+
+/**
+ * Perform ticket iteration step
+ *
+ * @param ti ticket iterator to process
+ */
+static void
+run_ticket_iteration_round (struct TicketIteration *ti)
+{
+ struct TicketIterationProcResult proc;
+ struct GNUNET_MQ_Envelope *env;
+ struct TicketResultMessage *trm;
+ int ret;
+
+ memset (&proc, 0, sizeof (proc));
+ proc.ti = ti;
+ proc.res_iteration_finished = IT_START;
+ while (IT_START == proc.res_iteration_finished)
+ {
+ if (GNUNET_SYSERR ==
+ (ret = TKT_database->iterate_tickets (TKT_database->cls,
+ &ti->identity,
+ ti->is_audience,
+ ti->offset,
+ &ticket_iterate_proc,
+ &proc)))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ if (GNUNET_NO == ret)
+ proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
+ ti->offset++;
+ }
+ if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "More results available\n");
+ return; /* more later */
+ }
+ /* send empty response to indicate end of list */
+ env = GNUNET_MQ_msg (trm,
+ GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT);
+ trm->id = htonl (ti->r_id);
+ GNUNET_MQ_send (ti->client->mq,
+ env);
+ GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
+ ti->client->ticket_iter_tail,
+ ti);
+ GNUNET_free (ti);
+}
+
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START message
+ *
+ * @param cls the client sending the message
+ * @param tis_msg message from the client
+ */
+static void
+handle_ticket_iteration_start (void *cls,
+ const struct TicketIterationStartMessage *tis_msg)
+{
+ struct IdpClient *client = cls;
+ struct TicketIteration *ti;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received TICKET_ITERATION_START message\n");
+ ti = GNUNET_new (struct TicketIteration);
+ ti->r_id = ntohl (tis_msg->id);
+ ti->offset = 0;
+ ti->client = client;
+ ti->identity = tis_msg->identity;
+ ti->is_audience = ntohl (tis_msg->is_audience);
+
+ GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
+ client->ticket_iter_tail,
+ ti);
+ run_ticket_iteration_round (ti);
+ GNUNET_SERVICE_client_continue (client->client);
+}
+
+
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP message
+ *
+ * @param cls the client sending the message
+ * @param tis_msg message from the client
+ */
+static void
+handle_ticket_iteration_stop (void *cls,
+ const struct TicketIterationStopMessage *tis_msg)
+{
+ struct IdpClient *client = cls;
+ struct TicketIteration *ti;
+ uint32_t rid;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received `%s' message\n",
+ "TICKET_ITERATION_STOP");
+ rid = ntohl (tis_msg->id);
+ for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
+ if (ti->r_id == rid)
+ break;
+ if (NULL == ti)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (client->client);
+ return;
+ }
+ GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
+ client->ticket_iter_tail,
+ ti);
+ GNUNET_free (ti);
+ GNUNET_SERVICE_client_continue (client->client);
+}
+
+
+/**
+ * Handles a #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT message
+ *
+ * @param cls the client sending the message
+ * @param message message from the client
+ */
+static void
+handle_ticket_iteration_next (void *cls,
+ const struct TicketIterationNextMessage *tis_msg)
+{
+ struct IdpClient *client = cls;
+ struct TicketIteration *ti;
+ uint32_t rid;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received TICKET_ITERATION_NEXT message\n");
+ rid = ntohl (tis_msg->id);
+ for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
+ if (ti->r_id == rid)
+ break;
+ if (NULL == ti)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (client->client);
+ return;
+ }
+ run_ticket_iteration_round (ti);
+ GNUNET_SERVICE_client_continue (client->client);
+}
+
const struct GNUNET_CONFIGURATION_Handle *c,
struct GNUNET_SERVICE_Handle *server)
{
+ char *database;
cfg = c;
stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
NULL,
NULL);
+ /* Loading DB plugin */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "identity-provider",
+ "database",
+ &database))
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "No database backend configured\n");
+ GNUNET_asprintf (&db_lib_name,
+ "libgnunet_plugin_identity_provider_%s",
+ database);
+ TKT_database = GNUNET_PLUGIN_load (db_lib_name,
+ (void *) cfg);
+ GNUNET_free (database);
+ if (NULL == TKT_database)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not load database backend `%s'\n",
+ db_lib_name);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
if (GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_time (cfg,
"identity-provider",
GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET,
struct ConsumeTicketMessage,
NULL),
+ GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
+ GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START,
+ struct TicketIterationStartMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
+ GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT,
+ struct TicketIterationNextMessage,
+ NULL),
+ GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
+ GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP,
+ struct TicketIterationStopMessage,
+ NULL),
+
GNUNET_MQ_handler_end());
-/* end of gnunet-service-identity-provider.c */
+ /* end of gnunet-service-identity-provider.c */
UNIX_MATCH_UID = NO
UNIX_MATCH_GID = YES
TOKEN_EXPIRATION_INTERVAL = 30 m
+
+[identity-provider-sqlite]
+FILENAME = $GNUNET_DATA_HOME/identity-provider/sqlite.db
return attrs;
}
+void
+attribute_list_destroy (struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs)
+{
+ struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *le;
+ struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *tmp_le;
+
+ for (le = attrs->list_head; NULL != le;)
+ {
+ GNUNET_free (le->attribute);
+ tmp_le = le;
+ le = le->next;
+ GNUNET_free (tmp_le);
+ }
+ GNUNET_free (attrs);
+}
size_t
attribute_serialize_get_size (const struct GNUNET_IDENTITY_PROVIDER_Attribute *attr)
size_t
attribute_list_serialize_get_size (const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
+void
+attribute_list_destroy (struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
/**
};
+/**
+ * Start a ticket iteration for the given identity
+ */
+struct TicketIterationStartMessage
+{
+ /**
+ * Message
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Unique identifier for this request (for key collisions).
+ */
+ uint32_t id GNUNET_PACKED;
+
+ /**
+ * Identity.
+ */
+ struct GNUNET_CRYPTO_EcdsaPublicKey identity;
+
+ /**
+ * Identity is audience or issuer
+ */
+ uint32_t is_audience GNUNET_PACKED;
+};
+
+
+/**
+ * Ask for next result of ticket iteration for the given operation
+ */
+struct TicketIterationNextMessage
+{
+ /**
+ * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Unique identifier for this request (for key collisions).
+ */
+ uint32_t id GNUNET_PACKED;
+
+};
+
+
+/**
+ * Stop ticket iteration for the given operation
+ */
+struct TicketIterationStopMessage
+{
+ /**
+ * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Unique identifier for this request (for key collisions).
+ */
+ uint32_t id GNUNET_PACKED;
+
+};
+
+
+
/**
* Ticket issue message
*/
--- /dev/null
+ /*
+ * This file is part of GNUnet
+ * Copyright (C) 2009-2017 GNUnet e.V.
+ *
+ * GNUnet is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your
+ * option) any later version.
+ *
+ * GNUnet 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNUnet; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * @file identity-provider/plugin_identity_provider_sqlite.c
+ * @brief sqlite-based idp backend
+ * @author Martin Schanzenbach
+ */
+
+#include "platform.h"
+#include "gnunet_identity_provider_service.h"
+#include "gnunet_identity_provider_plugin.h"
+#include "identity_attribute.h"
+#include "gnunet_sq_lib.h"
+#include <sqlite3.h>
+
+/**
+ * After how many ms "busy" should a DB operation fail for good? A
+ * low value makes sure that we are more responsive to requests
+ * (especially PUTs). A high value guarantees a higher success rate
+ * (SELECTs in iterate can take several seconds despite LIMIT=1).
+ *
+ * The default value of 1s should ensure that users do not experience
+ * huge latencies while at the same time allowing operations to
+ * succeed with reasonable probability.
+ */
+#define BUSY_TIMEOUT_MS 1000
+
+
+/**
+ * Log an error message at log-level 'level' that indicates
+ * a failure of the command 'cmd' on file 'filename'
+ * with the message given by strerror(errno).
+ */
+#define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "namestore-identity-provider", _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh)); } while(0)
+
+#define LOG(kind,...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__)
+
+
+/**
+ * Context for all functions in this plugin.
+ */
+struct Plugin
+{
+
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Database filename.
+ */
+ char *fn;
+
+ /**
+ * Native SQLite database handle.
+ */
+ sqlite3 *dbh;
+
+ /**
+ * Precompiled SQL to store ticket.
+ */
+ sqlite3_stmt *store_ticket;
+
+ /**
+ * Precompiled SQL to delete existing ticket.
+ */
+ sqlite3_stmt *delete_ticket;
+
+ /**
+ * Precompiled SQL to iterate tickets.
+ */
+ sqlite3_stmt *iterate_tickets;
+
+ /**
+ * Precompiled SQL to iterate tickets by audience.
+ */
+ sqlite3_stmt *iterate_tickets_by_audience;
+};
+
+
+/**
+ * @brief Prepare a SQL statement
+ *
+ * @param dbh handle to the database
+ * @param zSql SQL statement, UTF-8 encoded
+ * @param ppStmt set to the prepared statement
+ * @return 0 on success
+ */
+static int
+sq_prepare (sqlite3 *dbh,
+ const char *zSql,
+ sqlite3_stmt **ppStmt)
+{
+ char *dummy;
+ int result;
+
+ result =
+ sqlite3_prepare_v2 (dbh,
+ zSql,
+ strlen (zSql),
+ ppStmt,
+ (const char **) &dummy);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Prepared `%s' / %p: %d\n",
+ zSql,
+ *ppStmt,
+ result);
+ return result;
+}
+
+/**
+ * Create our database indices.
+ *
+ * @param dbh handle to the database
+ */
+static void
+create_indices (sqlite3 * dbh)
+{
+ /* create indices */
+ if ( (SQLITE_OK !=
+ sqlite3_exec (dbh,
+ "CREATE INDEX IF NOT EXISTS identity_reverse ON identity001tickets (identity,audience)",
+ NULL, NULL, NULL)) ||
+ (SQLITE_OK !=
+ sqlite3_exec (dbh,
+ "CREATE INDEX IF NOT EXISTS it_iter ON identity001tickets (rnd)",
+ NULL, NULL, NULL)) )
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to create indices: %s\n",
+ sqlite3_errmsg (dbh));
+}
+
+
+
+#if 0
+#define CHECK(a) GNUNET_break(a)
+#define ENULL NULL
+#else
+#define ENULL &e
+#define ENULL_DEFINED 1
+#define CHECK(a) if (! (a)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); }
+#endif
+
+
+/**
+ * Initialize the database connections and associated
+ * data structures (create tables and indices
+ * as needed as well).
+ *
+ * @param plugin the plugin context (state for this module)
+ * @return #GNUNET_OK on success
+ */
+static int
+database_setup (struct Plugin *plugin)
+{
+ sqlite3_stmt *stmt;
+ char *afsdir;
+#if ENULL_DEFINED
+ char *e;
+#endif
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
+ "identity-provider-sqlite",
+ "FILENAME",
+ &afsdir))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "identity-provider-sqlite",
+ "FILENAME");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_DISK_file_test (afsdir))
+ {
+ if (GNUNET_OK !=
+ GNUNET_DISK_directory_create_for_file (afsdir))
+ {
+ GNUNET_break (0);
+ GNUNET_free (afsdir);
+ return GNUNET_SYSERR;
+ }
+ }
+ /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
+ plugin->fn = afsdir;
+
+ /* Open database and precompile statements */
+ if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Unable to initialize SQLite: %s.\n"),
+ sqlite3_errmsg (plugin->dbh));
+ return GNUNET_SYSERR;
+ }
+ CHECK (SQLITE_OK ==
+ sqlite3_exec (plugin->dbh,
+ "PRAGMA temp_store=MEMORY", NULL, NULL,
+ ENULL));
+ CHECK (SQLITE_OK ==
+ sqlite3_exec (plugin->dbh,
+ "PRAGMA synchronous=NORMAL", NULL, NULL,
+ ENULL));
+ CHECK (SQLITE_OK ==
+ sqlite3_exec (plugin->dbh,
+ "PRAGMA legacy_file_format=OFF", NULL, NULL,
+ ENULL));
+ CHECK (SQLITE_OK ==
+ sqlite3_exec (plugin->dbh,
+ "PRAGMA auto_vacuum=INCREMENTAL", NULL,
+ NULL, ENULL));
+ CHECK (SQLITE_OK ==
+ sqlite3_exec (plugin->dbh,
+ "PRAGMA encoding=\"UTF-8\"", NULL,
+ NULL, ENULL));
+ CHECK (SQLITE_OK ==
+ sqlite3_exec (plugin->dbh,
+ "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL,
+ ENULL));
+ CHECK (SQLITE_OK ==
+ sqlite3_exec (plugin->dbh,
+ "PRAGMA page_size=4092", NULL, NULL,
+ ENULL));
+
+ CHECK (SQLITE_OK ==
+ sqlite3_busy_timeout (plugin->dbh,
+ BUSY_TIMEOUT_MS));
+
+
+ /* Create table */
+ CHECK (SQLITE_OK ==
+ sq_prepare (plugin->dbh,
+ "SELECT 1 FROM sqlite_master WHERE tbl_name = 'identity001tickets'",
+ &stmt));
+ if ((sqlite3_step (stmt) == SQLITE_DONE) &&
+ (sqlite3_exec
+ (plugin->dbh,
+ "CREATE TABLE identity001tickets ("
+ " identity BLOB NOT NULL DEFAULT '',"
+ " audience BLOB NOT NULL DEFAULT '',"
+ " rnd INT8 NOT NULL DEFAULT '',"
+ " attributes BLOB NOT NULL DEFAULT ''"
+ ")",
+ NULL, NULL, NULL) != SQLITE_OK))
+ {
+ LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR,
+ "sqlite3_exec");
+ sqlite3_finalize (stmt);
+ return GNUNET_SYSERR;
+ }
+ sqlite3_finalize (stmt);
+
+ create_indices (plugin->dbh);
+
+ if ( (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "INSERT INTO identity001tickets (identity, audience, rnd, attributes)"
+ " VALUES (?, ?, ?, ?)",
+ &plugin->store_ticket)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "DELETE FROM identity001tickets WHERE identity=? AND rnd=?",
+ &plugin->delete_ticket)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT identity,audience,rnd,attributes"
+ " FROM identity001tickets WHERE identity=?"
+ " ORDER BY rnd LIMIT 1 OFFSET ?",
+ &plugin->iterate_tickets)) ||
+ (SQLITE_OK !=
+ sq_prepare (plugin->dbh,
+ "SELECT identity,audience,rnd,attributes"
+ " FROM identity001tickets WHERE audience=?"
+ " ORDER BY rnd LIMIT 1 OFFSET ?",
+ &plugin->iterate_tickets_by_audience)) )
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR,
+ "precompiling");
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown database connection and associate data
+ * structures.
+ * @param plugin the plugin context (state for this module)
+ */
+static void
+database_shutdown (struct Plugin *plugin)
+{
+ int result;
+ sqlite3_stmt *stmt;
+
+ if (NULL != plugin->store_ticket)
+ sqlite3_finalize (plugin->store_ticket);
+ if (NULL != plugin->delete_ticket)
+ sqlite3_finalize (plugin->delete_ticket);
+ if (NULL != plugin->iterate_tickets)
+ sqlite3_finalize (plugin->iterate_tickets);
+ result = sqlite3_close (plugin->dbh);
+ if (result == SQLITE_BUSY)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Tried to close sqlite without finalizing all prepared statements.\n"));
+ stmt = sqlite3_next_stmt (plugin->dbh,
+ NULL);
+ while (NULL != stmt)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite",
+ "Closing statement %p\n",
+ stmt);
+ result = sqlite3_finalize (stmt);
+ if (result != SQLITE_OK)
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
+ "sqlite",
+ "Failed to close statement %p: %d\n",
+ stmt,
+ result);
+ stmt = sqlite3_next_stmt (plugin->dbh,
+ NULL);
+ }
+ result = sqlite3_close (plugin->dbh);
+ }
+ if (SQLITE_OK != result)
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR,
+ "sqlite3_close");
+
+ GNUNET_free_non_null (plugin->fn);
+}
+
+
+/**
+ * Store a ticket in the database.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param ticket the ticket to persist
+ * @param attrs attributes to persist
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+static int
+identity_provider_sqlite_store_ticket (void *cls,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
+ const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs)
+{
+ struct Plugin *plugin = cls;
+ int n;
+ size_t attrs_size;
+ char *attrs_serialized;
+
+ attrs_size = attribute_list_serialize_get_size (attrs);
+
+ attrs_serialized = GNUNET_malloc (attrs_size);
+
+ attribute_list_serialize (attrs,
+ attrs_serialized);
+
+ {
+ struct GNUNET_SQ_QueryParam sparams[] = {
+ GNUNET_SQ_query_param_auto_from_type (&ticket->identity),
+ GNUNET_SQ_query_param_auto_from_type (&ticket->audience),
+ GNUNET_SQ_query_param_uint64 (&ticket->rnd),
+ GNUNET_SQ_query_param_fixed_size (attrs_serialized, attrs_size),
+ GNUNET_SQ_query_param_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (plugin->store_ticket,
+ sparams))
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_bind_XXXX");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->store_ticket);
+ return GNUNET_SYSERR;
+ }
+ n = sqlite3_step (plugin->store_ticket);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->store_ticket);
+ }
+ switch (n)
+ {
+ case SQLITE_DONE:
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite",
+ "Ticket stored\n");
+ return GNUNET_OK;
+ case SQLITE_BUSY:
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_step");
+ return GNUNET_NO;
+ default:
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_step");
+ return GNUNET_SYSERR;
+ }
+}
+
+
+/**
+ * Store a ticket in the database.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param ticket the ticket to delete
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+static int
+identity_provider_sqlite_delete_ticket (void *cls,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket)
+{
+ struct Plugin *plugin = cls;
+ int n;
+
+ {
+ struct GNUNET_SQ_QueryParam sparams[] = {
+ GNUNET_SQ_query_param_auto_from_type (&ticket->identity),
+ GNUNET_SQ_query_param_uint64 (&ticket->rnd),
+ GNUNET_SQ_query_param_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_SQ_bind (plugin->delete_ticket,
+ sparams))
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_bind_XXXX");
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->store_ticket);
+ return GNUNET_SYSERR;
+ }
+ n = sqlite3_step (plugin->delete_ticket);
+ GNUNET_SQ_reset (plugin->dbh,
+ plugin->delete_ticket);
+ }
+ switch (n)
+ {
+ case SQLITE_DONE:
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite",
+ "Ticket deleted\n");
+ return GNUNET_OK;
+ case SQLITE_BUSY:
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_step");
+ return GNUNET_NO;
+ default:
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_step");
+ return GNUNET_SYSERR;
+ }
+}
+
+
+/**
+ * The given 'sqlite' statement has been prepared to be run.
+ * It will return a record which should be given to the iterator.
+ * Runs the statement and parses the returned record.
+ *
+ * @param plugin plugin context
+ * @param stmt to run (and then clean up)
+ * @param iter iterator to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
+ */
+static int
+get_ticket_and_call_iterator (struct Plugin *plugin,
+ sqlite3_stmt *stmt,
+ GNUNET_IDENTITY_PROVIDER_TicketIterator iter,
+ void *iter_cls)
+{
+ struct GNUNET_IDENTITY_PROVIDER_Ticket2 ticket;
+ size_t attrs_size;
+ void *attrs_serialized;
+ int ret;
+ int sret;
+
+ ret = GNUNET_NO;
+ if (SQLITE_ROW == (sret = sqlite3_step (stmt)))
+ {
+ struct GNUNET_SQ_ResultSpec rs[] = {
+ GNUNET_SQ_result_spec_auto_from_type (&ticket.identity),
+ GNUNET_SQ_result_spec_auto_from_type (&ticket.audience),
+ GNUNET_SQ_result_spec_uint64 (&ticket.rnd),
+ GNUNET_SQ_result_spec_variable_size (&attrs_serialized, &attrs_size),
+ GNUNET_SQ_result_spec_end
+
+ };
+ ret = GNUNET_SQ_extract_result (stmt,
+ rs);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break (0);
+ ret = GNUNET_SYSERR;
+ }
+ else
+ {
+ struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs;
+
+ attrs = attribute_list_deserialize (attrs_serialized, attrs_size);
+
+ if (NULL == attrs)
+ {
+ GNUNET_break (0);
+ ret = GNUNET_SYSERR;
+ }
+ else
+ {
+ if (NULL != iter)
+ iter (iter_cls,
+ &ticket,
+ attrs);
+ ret = GNUNET_YES;
+ }
+ }
+ GNUNET_SQ_cleanup_result (rs);
+ }
+ else
+ {
+ if (SQLITE_DONE != sret)
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR,
+ "sqlite_step");
+ }
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ return ret;
+}
+
+/**
+ * Iterate over the results for a particular key and zone in the
+ * datastore. Will return at most one result to the iterator.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param identity the issuing identity or audience (depending on audience switch)
+ * @param audience GNUNET_YES if identity is audience
+ * @param offset offset in the list of all matching records
+ * @param iter function to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
+ */
+static int
+identity_provider_sqlite_iterate_tickets (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+ int audience,
+ uint64_t offset,
+ GNUNET_IDENTITY_PROVIDER_TicketIterator iter,
+ void *iter_cls)
+{
+ struct Plugin *plugin = cls;
+ sqlite3_stmt *stmt;
+ int err;
+
+ if (NULL == identity)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ struct GNUNET_SQ_QueryParam params[] = {
+ GNUNET_SQ_query_param_auto_from_type (identity),
+ GNUNET_SQ_query_param_uint64 (&offset),
+ GNUNET_SQ_query_param_end
+ };
+ if (GNUNET_YES == audience)
+ {
+ stmt = plugin->iterate_tickets_by_audience;
+ err = GNUNET_SQ_bind (stmt,
+ params);
+ }
+ else
+ {
+ stmt = plugin->iterate_tickets;
+ err = GNUNET_SQ_bind (stmt,
+ params);
+ }
+ if (GNUNET_OK != err)
+ {
+ LOG_SQLITE (plugin,
+ GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+ "sqlite3_bind_XXXX");
+ GNUNET_SQ_reset (plugin->dbh,
+ stmt);
+ return GNUNET_SYSERR;
+ }
+ return get_ticket_and_call_iterator (plugin,
+ stmt,
+ iter,
+ iter_cls);
+}
+
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls the "struct GNUNET_IDENTITY_PROVIDER_PluginEnvironment*"
+ * @return NULL on error, otherwise the plugin context
+ */
+void *
+libgnunet_plugin_identity_provider_sqlite_init (void *cls)
+{
+ static struct Plugin plugin;
+ const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+ struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *api;
+
+ if (NULL != plugin.cfg)
+ return NULL; /* can only initialize once! */
+ memset (&plugin, 0, sizeof (struct Plugin));
+ plugin.cfg = cfg;
+ if (GNUNET_OK != database_setup (&plugin))
+ {
+ database_shutdown (&plugin);
+ return NULL;
+ }
+ api = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_PluginFunctions);
+ api->cls = &plugin;
+ api->store_ticket = &identity_provider_sqlite_store_ticket;
+ api->delete_ticket = &identity_provider_sqlite_delete_ticket;
+ api->iterate_tickets = &identity_provider_sqlite_iterate_tickets;
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("Sqlite database running\n"));
+ return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ *
+ * @param cls the plugin context (as returned by "init")
+ * @return always NULL
+ */
+void *
+libgnunet_plugin_namestore_sqlite_done (void *cls)
+{
+ struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *api = cls;
+ struct Plugin *plugin = api->cls;
+
+ database_shutdown (plugin);
+ plugin->cfg = NULL;
+ GNUNET_free (api);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "sqlite plugin is finished\n");
+ return NULL;
+}
+
+/* end of plugin_identity_provider_sqlite.c */
--- /dev/null
+/*
+ This file is part of GNUnet
+ Copyright (C) 2012, 2013 GNUnet e.V.
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+ * @author Martin Schanzenbach
+ *
+ * @file
+ * Plugin API for the idp database backend
+ *
+ * @defgroup identity-provider-plugin IdP service plugin API
+ * Plugin API for the idp database backend
+ * @{
+ */
+#ifndef GNUNET_IDENTITY_PROVIDER_PLUGIN_H
+#define GNUNET_IDENTITY_PROVIDER_PLUGIN_H
+
+#include "gnunet_util_lib.h"
+#include "gnunet_identity_provider_service.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0 /* keep Emacsens' auto-indent happy */
+}
+#endif
+#endif
+
+
+/**
+ * Function called by for each matching ticket.
+ *
+ * @param cls closure
+ * @param ticket the ticket
+ * @prarm attrs the attributes
+ */
+typedef void (*GNUNET_IDENTITY_PROVIDER_TicketIterator) (void *cls,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
+ const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
+
+
+/**
+ * @brief struct returned by the initialization function of the plugin
+ */
+struct GNUNET_IDENTITY_PROVIDER_PluginFunctions
+{
+
+ /**
+ * Closure to pass to all plugin functions.
+ */
+ void *cls;
+
+ /**
+ * Store a ticket in the database.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param ticket the ticket to store
+ * @param attrs the attributes shared with the ticket
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+ int (*store_ticket) (void *cls,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
+ const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
+
+ /**
+ * Delete a ticket from the database.
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param ticket the ticket to store
+ * @return #GNUNET_OK on success, else #GNUNET_SYSERR
+ */
+ int (*delete_ticket) (void *cls,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket);
+
+
+
+ /**
+ * Iterate over all tickets
+ *
+ * @param cls closure (internal context for the plugin)
+ * @param identity the identity
+ * @param audience GNUNET_YES if the identity is the audience of the ticket
+ * else it is considered the issuer
+ * @param iter function to call with the result
+ * @param iter_cls closure for @a iter
+ * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
+ */
+ int (*iterate_tickets) (void *cls,
+ const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
+ int audience,
+ uint64_t offset,
+ GNUNET_IDENTITY_PROVIDER_TicketIterator iter, void *iter_cls);
+
+
+};
+
+
+#if 0 /* keep Emacsens' auto-indent happy */
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/** @} */ /* end of group */
* token
*
* @param cls closure
- * @param grant the label in GNS pointing to the token
* @param ticket the ticket
- * @param token the issued token
- * @param name name assigned by the user for this ego,
- * NULL if the user just deleted the ego and it
- * must thus no longer be used
*/
typedef void
(*GNUNET_IDENTITY_PROVIDER_TicketCallback)(void *cls,
const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket);
+/**
+ * Method called when issued tickets are retrieved. Also returns the attributes
+ * that were issued at the time.
+ *
+ * @param cls closure
+ * @param ticket the ticket
+ * @param attrs the attributes as list
+ */
+typedef void
+(*GNUNET_IDENTITY_PROVIDER_TicketResult)(void *cls,
+ const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
+ const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
+
/**
* Issues a ticket to another identity. The identity may use
-/** TODO
+/**
* Consumes an issued ticket. The ticket is persisted
* and used to retrieve identity information from the issuer
*
#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET 973
+#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START 974
+
+#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP 975
+
+#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT 976
+
/**************************************************
*
* CREDENTIAL MESSAGE TYPES