aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSchanzenbach, Martin <mschanzenbach@posteo.de>2017-10-05 19:59:39 +0200
committerSchanzenbach, Martin <mschanzenbach@posteo.de>2017-10-05 19:59:39 +0200
commit76817ee408cff4aee534d6016423c8a4ecb5555f (patch)
tree651e556acb0d7b057f7bff4af6fdfc232165090c /src
parent2b0c260c3ceab5b2d5a4c3a04f7e2a0a357e9d75 (diff)
downloadgnunet-76817ee408cff4aee534d6016423c8a4ecb5555f.tar.gz
gnunet-76817ee408cff4aee534d6016423c8a4ecb5555f.zip
-add ticket DB for IdP
Diffstat (limited to 'src')
-rw-r--r--src/identity-provider/Makefile.am19
-rw-r--r--src/identity-provider/gnunet-service-identity-provider.c411
-rw-r--r--src/identity-provider/identity-provider.conf3
-rw-r--r--src/identity-provider/identity_attribute.c15
-rw-r--r--src/identity-provider/identity_attribute.h2
-rw-r--r--src/identity-provider/identity_provider.h64
-rw-r--r--src/identity-provider/plugin_identity_provider_sqlite.c669
-rw-r--r--src/include/gnunet_identity_provider_plugin.h123
-rw-r--r--src/include/gnunet_identity_provider_service.h20
-rw-r--r--src/include/gnunet_protocols.h6
10 files changed, 1294 insertions, 38 deletions
diff --git a/src/identity-provider/Makefile.am b/src/identity-provider/Makefile.am
index 106c8a92b..1b35c6c04 100644
--- a/src/identity-provider/Makefile.am
+++ b/src/identity-provider/Makefile.am
@@ -12,6 +12,10 @@ if USE_COVERAGE
12 XLIB = -lgcov 12 XLIB = -lgcov
13endif 13endif
14 14
15if HAVE_SQLITE
16SQLITE_PLUGIN = libgnunet_plugin_identity_provider_sqlite.la
17endif
18
15pkgcfgdir= $(pkgdatadir)/config.d/ 19pkgcfgdir= $(pkgdatadir)/config.d/
16 20
17libexecdir= $(pkglibdir)/libexec/ 21libexecdir= $(pkglibdir)/libexec/
@@ -23,7 +27,8 @@ lib_LTLIBRARIES = \
23 libgnunetidentityprovider.la 27 libgnunetidentityprovider.la
24plugin_LTLIBRARIES = \ 28plugin_LTLIBRARIES = \
25 libgnunet_plugin_rest_identity_provider.la \ 29 libgnunet_plugin_rest_identity_provider.la \
26 libgnunet_plugin_gnsrecord_identity_provider.la 30 libgnunet_plugin_gnsrecord_identity_provider.la \
31 $(SQLITE_PLUGIN)
27 32
28bin_PROGRAMS = \ 33bin_PROGRAMS = \
29 gnunet-identity-token \ 34 gnunet-identity-token \
@@ -40,6 +45,18 @@ libgnunet_plugin_gnsrecord_identity_provider_la_LIBADD = \
40libgnunet_plugin_gnsrecord_identity_provider_la_LDFLAGS = \ 45libgnunet_plugin_gnsrecord_identity_provider_la_LDFLAGS = \
41 $(GN_PLUGIN_LDFLAGS) 46 $(GN_PLUGIN_LDFLAGS)
42 47
48libgnunet_plugin_identity_provider_sqlite_la_SOURCES = \
49 plugin_identity_provider_sqlite.c
50libgnunet_plugin_identity_provider_sqlite_la_LIBADD = \
51 $(top_builddir)/src/identity-provider/libgnunetidentityprovider.la \
52 $(top_builddir)/src/sq/libgnunetsq.la \
53 $(top_builddir)/src/statistics/libgnunetstatistics.la \
54 $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \
55 $(LTLIBINTL)
56libgnunet_plugin_identity_provider_sqlite_la_LDFLAGS = \
57 $(GN_PLUGIN_LDFLAGS)
58
59
43 60
44gnunet_service_identity_provider_SOURCES = \ 61gnunet_service_identity_provider_SOURCES = \
45 gnunet-service-identity-provider.c \ 62 gnunet-service-identity-provider.c \
diff --git a/src/identity-provider/gnunet-service-identity-provider.c b/src/identity-provider/gnunet-service-identity-provider.c
index 9a919102f..f77eebd6d 100644
--- a/src/identity-provider/gnunet-service-identity-provider.c
+++ b/src/identity-provider/gnunet-service-identity-provider.c
@@ -33,6 +33,7 @@
33#include "gnunet_credential_service.h" 33#include "gnunet_credential_service.h"
34#include "gnunet_statistics_service.h" 34#include "gnunet_statistics_service.h"
35#include "gnunet_gns_service.h" 35#include "gnunet_gns_service.h"
36#include "gnunet_identity_provider_plugin.h"
36#include "gnunet_signatures.h" 37#include "gnunet_signatures.h"
37#include "identity_provider.h" 38#include "identity_provider.h"
38#include "identity_token.h" 39#include "identity_token.h"
@@ -65,6 +66,16 @@
65static struct GNUNET_IDENTITY_Handle *identity_handle; 66static struct GNUNET_IDENTITY_Handle *identity_handle;
66 67
67/** 68/**
69 * Database handle
70 */
71static struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *TKT_database;
72
73/**
74 * Name of DB plugin
75 */
76static char *db_lib_name;
77
78/**
68 * Token expiration interval 79 * Token expiration interval
69 */ 80 */
70static struct GNUNET_TIME_Relative token_expiration_interval; 81static struct GNUNET_TIME_Relative token_expiration_interval;
@@ -136,6 +147,54 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg;
136struct IdpClient; 147struct IdpClient;
137 148
138/** 149/**
150 * A ticket iteration operation.
151 */
152struct TicketIteration
153{
154 /**
155 * DLL
156 */
157 struct TicketIteration *next;
158
159 /**
160 * DLL
161 */
162 struct TicketIteration *prev;
163
164 /**
165 * Client which intiated this zone iteration
166 */
167 struct IdpClient *client;
168
169 /**
170 * Key of the identity we are iterating over.
171 */
172 struct GNUNET_CRYPTO_EcdsaPublicKey identity;
173
174 /**
175 * Identity is audience
176 */
177 uint32_t is_audience;
178
179 /**
180 * The operation id fot the iteration in the response for the client
181 */
182 uint32_t r_id;
183
184 /**
185 * Offset of the iteration used to address next result of the
186 * iteration in the store
187 *
188 * Initialy set to 0 in handle_iteration_start
189 * Incremented with by every call to handle_iteration_next
190 */
191 uint32_t offset;
192
193};
194
195
196
197/**
139 * Callback after an ABE bootstrap 198 * Callback after an ABE bootstrap
140 * 199 *
141 * @param cls closure 200 * @param cls closure
@@ -247,6 +306,16 @@ struct IdpClient
247 * in progress initiated by this client 306 * in progress initiated by this client
248 */ 307 */
249 struct AttributeIterator *op_tail; 308 struct AttributeIterator *op_tail;
309
310 /**
311 * Head of DLL of ticket iteration ops
312 */
313 struct TicketIteration *ticket_iter_head;
314
315 /**
316 * Tail of DLL of ticket iteration ops
317 */
318 struct TicketIteration *ticket_iter_tail;
250}; 319};
251 320
252 321
@@ -605,7 +674,10 @@ cleanup()
605 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 674 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
606 stats = NULL; 675 stats = NULL;
607 } 676 }
608 677 GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name,
678 TKT_database));
679 GNUNET_free (db_lib_name);
680 db_lib_name = NULL;
609 if (NULL != timeout_task) 681 if (NULL != timeout_task)
610 GNUNET_SCHEDULER_cancel (timeout_task); 682 GNUNET_SCHEDULER_cancel (timeout_task);
611 if (NULL != update_task) 683 if (NULL != update_task)
@@ -1666,31 +1738,48 @@ handle_issue_message (void *cls,
1666static void 1738static void
1667cleanup_ticket_issue_handle (struct TicketIssueHandle *handle) 1739cleanup_ticket_issue_handle (struct TicketIssueHandle *handle)
1668{ 1740{
1669 struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *le; 1741 if (NULL != handle->attrs)
1670 struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *tmp_le; 1742 attribute_list_destroy (handle->attrs);
1671
1672 for (le = handle->attrs->list_head; NULL != le;)
1673 {
1674 GNUNET_free (le->attribute);
1675 tmp_le = le;
1676 le = le->next;
1677 GNUNET_free (tmp_le);
1678 }
1679 GNUNET_free (handle->attrs);
1680 if (NULL != handle->ns_qe) 1743 if (NULL != handle->ns_qe)
1681 GNUNET_NAMESTORE_cancel (handle->ns_qe); 1744 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1682 GNUNET_free (handle); 1745 GNUNET_free (handle);
1683} 1746}
1684 1747
1748
1749static void
1750send_ticket_result (struct IdpClient *client,
1751 uint32_t r_id,
1752 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
1753 const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs)
1754{
1755 struct TicketResultMessage *irm;
1756 struct GNUNET_MQ_Envelope *env;
1757 size_t attrs_size;
1758 struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket_buf;
1759 char *attrs_buf;
1760
1761 attrs_size = attribute_list_serialize_get_size (attrs);
1762
1763 env = GNUNET_MQ_msg_extra (irm,
1764 sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket2) + attrs_size,
1765 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT);
1766 ticket_buf = (struct GNUNET_IDENTITY_PROVIDER_Ticket2 *)&irm[1];
1767 *ticket_buf = *ticket;
1768 attrs_buf = (char*)&ticket_buf[1];
1769 attribute_list_serialize (attrs,
1770 attrs_buf);
1771 irm->id = htonl (r_id);
1772
1773 GNUNET_MQ_send (client->mq,
1774 env);
1775}
1776
1685static void 1777static void
1686store_ticket_issue_cont (void *cls, 1778store_ticket_issue_cont (void *cls,
1687 int32_t success, 1779 int32_t success,
1688 const char *emsg) 1780 const char *emsg)
1689{ 1781{
1690 struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket;
1691 struct TicketIssueHandle *handle = cls; 1782 struct TicketIssueHandle *handle = cls;
1692 struct TicketResultMessage *irm;
1693 struct GNUNET_MQ_Envelope *env;
1694 1783
1695 handle->ns_qe = NULL; 1784 handle->ns_qe = NULL;
1696 if (GNUNET_SYSERR == success) 1785 if (GNUNET_SYSERR == success)
@@ -1701,15 +1790,10 @@ store_ticket_issue_cont (void *cls,
1701 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); 1790 GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1702 return; 1791 return;
1703 } 1792 }
1704 env = GNUNET_MQ_msg_extra (irm, 1793 send_ticket_result (handle->client,
1705 sizeof (struct GNUNET_IDENTITY_PROVIDER_Ticket2), 1794 handle->r_id,
1706 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT); 1795 &handle->ticket,
1707 ticket = (struct GNUNET_IDENTITY_PROVIDER_Ticket2 *)&irm[1]; 1796 handle->attrs);
1708 *ticket = handle->ticket;
1709 irm->id = handle->r_id;
1710
1711 GNUNET_MQ_send (handle->client->mq,
1712 env);
1713 cleanup_ticket_issue_handle (handle); 1797 cleanup_ticket_issue_handle (handle);
1714} 1798}
1715 1799
@@ -1717,9 +1801,9 @@ store_ticket_issue_cont (void *cls,
1717 1801
1718int 1802int
1719serialize_abe_keyinfo2 (const struct TicketIssueHandle *handle, 1803serialize_abe_keyinfo2 (const struct TicketIssueHandle *handle,
1720 const struct GNUNET_CRYPTO_AbeKey *rp_key, 1804 const struct GNUNET_CRYPTO_AbeKey *rp_key,
1721 struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey, 1805 struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
1722 char **result) 1806 char **result)
1723{ 1807{
1724 struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey; 1808 struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
1725 struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *le; 1809 struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *le;
@@ -1729,12 +1813,12 @@ serialize_abe_keyinfo2 (const struct TicketIssueHandle *handle,
1729 char *write_ptr; 1813 char *write_ptr;
1730 char attrs_str_len; 1814 char attrs_str_len;
1731 ssize_t size; 1815 ssize_t size;
1732 1816
1733 struct GNUNET_CRYPTO_SymmetricSessionKey skey; 1817 struct GNUNET_CRYPTO_SymmetricSessionKey skey;
1734 struct GNUNET_CRYPTO_SymmetricInitializationVector iv; 1818 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1735 struct GNUNET_HashCode new_key_hash; 1819 struct GNUNET_HashCode new_key_hash;
1736 ssize_t enc_size; 1820 ssize_t enc_size;
1737 1821
1738 size = GNUNET_CRYPTO_cpabe_serialize_key (rp_key, 1822 size = GNUNET_CRYPTO_cpabe_serialize_key (rp_key,
1739 (void**)&serialized_key); 1823 (void**)&serialized_key);
1740 attrs_str_len = 0; 1824 attrs_str_len = 0;
@@ -1889,7 +1973,7 @@ handle_ticket_issue_message (void *cls,
1889 ih = GNUNET_new (struct TicketIssueHandle); 1973 ih = GNUNET_new (struct TicketIssueHandle);
1890 attrs_len = ntohs (im->attr_len); 1974 attrs_len = ntohs (im->attr_len);
1891 ih->attrs = attribute_list_deserialize ((char*)&im[1], attrs_len); 1975 ih->attrs = attribute_list_deserialize ((char*)&im[1], attrs_len);
1892 ih->r_id = im->id; 1976 ih->r_id = ntohl (im->id);
1893 ih->client = idp; 1977 ih->client = idp;
1894 ih->identity = im->identity; 1978 ih->identity = im->identity;
1895 GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity, 1979 GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity,
@@ -2488,6 +2572,234 @@ handle_iteration_next (void *cls,
2488 GNUNET_SERVICE_client_continue (idp->client); 2572 GNUNET_SERVICE_client_continue (idp->client);
2489} 2573}
2490 2574
2575/**
2576 * Ticket iteration processor result
2577 */
2578enum ZoneIterationResult
2579{
2580 /**
2581 * Iteration start.
2582 */
2583 IT_START = 0,
2584
2585 /**
2586 * Found tickets,
2587 * Continue to iterate with next iteration_next call
2588 */
2589 IT_SUCCESS_MORE_AVAILABLE = 1,
2590
2591 /**
2592 * Iteration complete
2593 */
2594 IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2
2595};
2596
2597
2598/**
2599 * Context for ticket iteration
2600 */
2601struct TicketIterationProcResult
2602{
2603 /**
2604 * The ticket iteration handle
2605 */
2606 struct TicketIteration *ti;
2607
2608 /**
2609 * Iteration result: iteration done?
2610 * #IT_SUCCESS_MORE_AVAILABLE: if there may be more results overall but
2611 * we got one for now and have sent it to the client
2612 * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
2613 * #IT_START: if we are still trying to find a result.
2614 */
2615 int res_iteration_finished;
2616
2617};
2618
2619
2620
2621/**
2622 * Process ticket from database
2623 *
2624 * @param cls struct TicketIterationProcResult
2625 * @param ticket the ticket
2626 * @param attrs the attributes
2627 */
2628static void
2629ticket_iterate_proc (void *cls,
2630 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
2631 const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs)
2632{
2633 struct TicketIterationProcResult *proc = cls;
2634
2635 if (NULL == ticket)
2636 {
2637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2638 "Iteration done\n");
2639 proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
2640 return;
2641 }
2642 if ((NULL == ticket) || (NULL == attrs))
2643 {
2644 /* error */
2645 proc->res_iteration_finished = IT_START;
2646 GNUNET_break (0);
2647 return;
2648 }
2649 proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
2650 send_ticket_result (proc->ti->client,
2651 proc->ti->r_id,
2652 ticket,
2653 attrs);
2654
2655}
2656
2657/**
2658 * Perform ticket iteration step
2659 *
2660 * @param ti ticket iterator to process
2661 */
2662static void
2663run_ticket_iteration_round (struct TicketIteration *ti)
2664{
2665 struct TicketIterationProcResult proc;
2666 struct GNUNET_MQ_Envelope *env;
2667 struct TicketResultMessage *trm;
2668 int ret;
2669
2670 memset (&proc, 0, sizeof (proc));
2671 proc.ti = ti;
2672 proc.res_iteration_finished = IT_START;
2673 while (IT_START == proc.res_iteration_finished)
2674 {
2675 if (GNUNET_SYSERR ==
2676 (ret = TKT_database->iterate_tickets (TKT_database->cls,
2677 &ti->identity,
2678 ti->is_audience,
2679 ti->offset,
2680 &ticket_iterate_proc,
2681 &proc)))
2682 {
2683 GNUNET_break (0);
2684 break;
2685 }
2686 if (GNUNET_NO == ret)
2687 proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
2688 ti->offset++;
2689 }
2690 if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
2691 {
2692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2693 "More results available\n");
2694 return; /* more later */
2695 }
2696 /* send empty response to indicate end of list */
2697 env = GNUNET_MQ_msg (trm,
2698 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_RESULT);
2699 trm->id = htonl (ti->r_id);
2700 GNUNET_MQ_send (ti->client->mq,
2701 env);
2702 GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
2703 ti->client->ticket_iter_tail,
2704 ti);
2705 GNUNET_free (ti);
2706}
2707
2708/**
2709 * Handles a #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START message
2710 *
2711 * @param cls the client sending the message
2712 * @param tis_msg message from the client
2713 */
2714static void
2715handle_ticket_iteration_start (void *cls,
2716 const struct TicketIterationStartMessage *tis_msg)
2717{
2718 struct IdpClient *client = cls;
2719 struct TicketIteration *ti;
2720
2721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2722 "Received TICKET_ITERATION_START message\n");
2723 ti = GNUNET_new (struct TicketIteration);
2724 ti->r_id = ntohl (tis_msg->id);
2725 ti->offset = 0;
2726 ti->client = client;
2727 ti->identity = tis_msg->identity;
2728 ti->is_audience = ntohl (tis_msg->is_audience);
2729
2730 GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
2731 client->ticket_iter_tail,
2732 ti);
2733 run_ticket_iteration_round (ti);
2734 GNUNET_SERVICE_client_continue (client->client);
2735}
2736
2737
2738/**
2739 * Handles a #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP message
2740 *
2741 * @param cls the client sending the message
2742 * @param tis_msg message from the client
2743 */
2744static void
2745handle_ticket_iteration_stop (void *cls,
2746 const struct TicketIterationStopMessage *tis_msg)
2747{
2748 struct IdpClient *client = cls;
2749 struct TicketIteration *ti;
2750 uint32_t rid;
2751
2752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2753 "Received `%s' message\n",
2754 "TICKET_ITERATION_STOP");
2755 rid = ntohl (tis_msg->id);
2756 for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2757 if (ti->r_id == rid)
2758 break;
2759 if (NULL == ti)
2760 {
2761 GNUNET_break (0);
2762 GNUNET_SERVICE_client_drop (client->client);
2763 return;
2764 }
2765 GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
2766 client->ticket_iter_tail,
2767 ti);
2768 GNUNET_free (ti);
2769 GNUNET_SERVICE_client_continue (client->client);
2770}
2771
2772
2773/**
2774 * Handles a #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT message
2775 *
2776 * @param cls the client sending the message
2777 * @param message message from the client
2778 */
2779static void
2780handle_ticket_iteration_next (void *cls,
2781 const struct TicketIterationNextMessage *tis_msg)
2782{
2783 struct IdpClient *client = cls;
2784 struct TicketIteration *ti;
2785 uint32_t rid;
2786
2787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2788 "Received TICKET_ITERATION_NEXT message\n");
2789 rid = ntohl (tis_msg->id);
2790 for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2791 if (ti->r_id == rid)
2792 break;
2793 if (NULL == ti)
2794 {
2795 GNUNET_break (0);
2796 GNUNET_SERVICE_client_drop (client->client);
2797 return;
2798 }
2799 run_ticket_iteration_round (ti);
2800 GNUNET_SERVICE_client_continue (client->client);
2801}
2802
2491 2803
2492 2804
2493 2805
@@ -2504,6 +2816,7 @@ run (void *cls,
2504 const struct GNUNET_CONFIGURATION_Handle *c, 2816 const struct GNUNET_CONFIGURATION_Handle *c,
2505 struct GNUNET_SERVICE_Handle *server) 2817 struct GNUNET_SERVICE_Handle *server)
2506{ 2818{
2819 char *database;
2507 cfg = c; 2820 cfg = c;
2508 2821
2509 stats = GNUNET_STATISTICS_create ("identity-provider", cfg); 2822 stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
@@ -2529,6 +2842,29 @@ run (void *cls,
2529 NULL, 2842 NULL,
2530 NULL); 2843 NULL);
2531 2844
2845 /* Loading DB plugin */
2846 if (GNUNET_OK !=
2847 GNUNET_CONFIGURATION_get_value_string (cfg,
2848 "identity-provider",
2849 "database",
2850 &database))
2851 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2852 "No database backend configured\n");
2853 GNUNET_asprintf (&db_lib_name,
2854 "libgnunet_plugin_identity_provider_%s",
2855 database);
2856 TKT_database = GNUNET_PLUGIN_load (db_lib_name,
2857 (void *) cfg);
2858 GNUNET_free (database);
2859 if (NULL == TKT_database)
2860 {
2861 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2862 "Could not load database backend `%s'\n",
2863 db_lib_name);
2864 GNUNET_SCHEDULER_shutdown ();
2865 return;
2866 }
2867
2532 if (GNUNET_OK == 2868 if (GNUNET_OK ==
2533 GNUNET_CONFIGURATION_get_value_time (cfg, 2869 GNUNET_CONFIGURATION_get_value_time (cfg,
2534 "identity-provider", 2870 "identity-provider",
@@ -2645,5 +2981,18 @@ GNUNET_SERVICE_MAIN
2645 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET, 2981 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET,
2646 struct ConsumeTicketMessage, 2982 struct ConsumeTicketMessage,
2647 NULL), 2983 NULL),
2984 GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
2985 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START,
2986 struct TicketIterationStartMessage,
2987 NULL),
2988 GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
2989 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT,
2990 struct TicketIterationNextMessage,
2991 NULL),
2992 GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
2993 GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP,
2994 struct TicketIterationStopMessage,
2995 NULL),
2996
2648 GNUNET_MQ_handler_end()); 2997 GNUNET_MQ_handler_end());
2649/* end of gnunet-service-identity-provider.c */ 2998 /* end of gnunet-service-identity-provider.c */
diff --git a/src/identity-provider/identity-provider.conf b/src/identity-provider/identity-provider.conf
index bac8e69ed..826b2419e 100644
--- a/src/identity-provider/identity-provider.conf
+++ b/src/identity-provider/identity-provider.conf
@@ -10,3 +10,6 @@ UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-identity-provider.sock
10UNIX_MATCH_UID = NO 10UNIX_MATCH_UID = NO
11UNIX_MATCH_GID = YES 11UNIX_MATCH_GID = YES
12TOKEN_EXPIRATION_INTERVAL = 30 m 12TOKEN_EXPIRATION_INTERVAL = 30 m
13
14[identity-provider-sqlite]
15FILENAME = $GNUNET_DATA_HOME/identity-provider/sqlite.db
diff --git a/src/identity-provider/identity_attribute.c b/src/identity-provider/identity_attribute.c
index 916386754..1c5654946 100644
--- a/src/identity-provider/identity_attribute.c
+++ b/src/identity-provider/identity_attribute.c
@@ -125,7 +125,22 @@ attribute_list_deserialize (const char* data,
125 return attrs; 125 return attrs;
126} 126}
127 127
128void
129attribute_list_destroy (struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs)
130{
131 struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *le;
132 struct GNUNET_IDENTITY_PROVIDER_AttributeListEntry *tmp_le;
133
134 for (le = attrs->list_head; NULL != le;)
135 {
136 GNUNET_free (le->attribute);
137 tmp_le = le;
138 le = le->next;
139 GNUNET_free (tmp_le);
140 }
141 GNUNET_free (attrs);
128 142
143}
129 144
130size_t 145size_t
131attribute_serialize_get_size (const struct GNUNET_IDENTITY_PROVIDER_Attribute *attr) 146attribute_serialize_get_size (const struct GNUNET_IDENTITY_PROVIDER_Attribute *attr)
diff --git a/src/identity-provider/identity_attribute.h b/src/identity-provider/identity_attribute.h
index 00e520a38..d44f4c17f 100644
--- a/src/identity-provider/identity_attribute.h
+++ b/src/identity-provider/identity_attribute.h
@@ -58,6 +58,8 @@ struct Attribute
58size_t 58size_t
59attribute_list_serialize_get_size (const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs); 59attribute_list_serialize_get_size (const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
60 60
61void
62attribute_list_destroy (struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
61 63
62 64
63/** 65/**
diff --git a/src/identity-provider/identity_provider.h b/src/identity-provider/identity_provider.h
index dcad35118..434af4d8c 100644
--- a/src/identity-provider/identity_provider.h
+++ b/src/identity-provider/identity_provider.h
@@ -319,6 +319,70 @@ struct AttributeIterationStopMessage
319}; 319};
320 320
321/** 321/**
322 * Start a ticket iteration for the given identity
323 */
324struct TicketIterationStartMessage
325{
326 /**
327 * Message
328 */
329 struct GNUNET_MessageHeader header;
330
331 /**
332 * Unique identifier for this request (for key collisions).
333 */
334 uint32_t id GNUNET_PACKED;
335
336 /**
337 * Identity.
338 */
339 struct GNUNET_CRYPTO_EcdsaPublicKey identity;
340
341 /**
342 * Identity is audience or issuer
343 */
344 uint32_t is_audience GNUNET_PACKED;
345};
346
347
348/**
349 * Ask for next result of ticket iteration for the given operation
350 */
351struct TicketIterationNextMessage
352{
353 /**
354 * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT
355 */
356 struct GNUNET_MessageHeader header;
357
358 /**
359 * Unique identifier for this request (for key collisions).
360 */
361 uint32_t id GNUNET_PACKED;
362
363};
364
365
366/**
367 * Stop ticket iteration for the given operation
368 */
369struct TicketIterationStopMessage
370{
371 /**
372 * Type will be #GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP
373 */
374 struct GNUNET_MessageHeader header;
375
376 /**
377 * Unique identifier for this request (for key collisions).
378 */
379 uint32_t id GNUNET_PACKED;
380
381};
382
383
384
385/**
322 * Ticket issue message 386 * Ticket issue message
323 */ 387 */
324struct TicketIssueMessage 388struct TicketIssueMessage
diff --git a/src/identity-provider/plugin_identity_provider_sqlite.c b/src/identity-provider/plugin_identity_provider_sqlite.c
new file mode 100644
index 000000000..d05baa79d
--- /dev/null
+++ b/src/identity-provider/plugin_identity_provider_sqlite.c
@@ -0,0 +1,669 @@
1 /*
2 * This file is part of GNUnet
3 * Copyright (C) 2009-2017 GNUnet e.V.
4 *
5 * GNUnet is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; either version 3, or (at your
8 * option) any later version.
9 *
10 * GNUnet is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with GNUnet; see the file COPYING. If not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21/**
22 * @file identity-provider/plugin_identity_provider_sqlite.c
23 * @brief sqlite-based idp backend
24 * @author Martin Schanzenbach
25 */
26
27#include "platform.h"
28#include "gnunet_identity_provider_service.h"
29#include "gnunet_identity_provider_plugin.h"
30#include "identity_attribute.h"
31#include "gnunet_sq_lib.h"
32#include <sqlite3.h>
33
34/**
35 * After how many ms "busy" should a DB operation fail for good? A
36 * low value makes sure that we are more responsive to requests
37 * (especially PUTs). A high value guarantees a higher success rate
38 * (SELECTs in iterate can take several seconds despite LIMIT=1).
39 *
40 * The default value of 1s should ensure that users do not experience
41 * huge latencies while at the same time allowing operations to
42 * succeed with reasonable probability.
43 */
44#define BUSY_TIMEOUT_MS 1000
45
46
47/**
48 * Log an error message at log-level 'level' that indicates
49 * a failure of the command 'cmd' on file 'filename'
50 * with the message given by strerror(errno).
51 */
52#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)
53
54#define LOG(kind,...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__)
55
56
57/**
58 * Context for all functions in this plugin.
59 */
60struct Plugin
61{
62
63 const struct GNUNET_CONFIGURATION_Handle *cfg;
64
65 /**
66 * Database filename.
67 */
68 char *fn;
69
70 /**
71 * Native SQLite database handle.
72 */
73 sqlite3 *dbh;
74
75 /**
76 * Precompiled SQL to store ticket.
77 */
78 sqlite3_stmt *store_ticket;
79
80 /**
81 * Precompiled SQL to delete existing ticket.
82 */
83 sqlite3_stmt *delete_ticket;
84
85 /**
86 * Precompiled SQL to iterate tickets.
87 */
88 sqlite3_stmt *iterate_tickets;
89
90 /**
91 * Precompiled SQL to iterate tickets by audience.
92 */
93 sqlite3_stmt *iterate_tickets_by_audience;
94};
95
96
97/**
98 * @brief Prepare a SQL statement
99 *
100 * @param dbh handle to the database
101 * @param zSql SQL statement, UTF-8 encoded
102 * @param ppStmt set to the prepared statement
103 * @return 0 on success
104 */
105static int
106sq_prepare (sqlite3 *dbh,
107 const char *zSql,
108 sqlite3_stmt **ppStmt)
109{
110 char *dummy;
111 int result;
112
113 result =
114 sqlite3_prepare_v2 (dbh,
115 zSql,
116 strlen (zSql),
117 ppStmt,
118 (const char **) &dummy);
119 LOG (GNUNET_ERROR_TYPE_DEBUG,
120 "Prepared `%s' / %p: %d\n",
121 zSql,
122 *ppStmt,
123 result);
124 return result;
125}
126
127/**
128 * Create our database indices.
129 *
130 * @param dbh handle to the database
131 */
132static void
133create_indices (sqlite3 * dbh)
134{
135 /* create indices */
136 if ( (SQLITE_OK !=
137 sqlite3_exec (dbh,
138 "CREATE INDEX IF NOT EXISTS identity_reverse ON identity001tickets (identity,audience)",
139 NULL, NULL, NULL)) ||
140 (SQLITE_OK !=
141 sqlite3_exec (dbh,
142 "CREATE INDEX IF NOT EXISTS it_iter ON identity001tickets (rnd)",
143 NULL, NULL, NULL)) )
144 LOG (GNUNET_ERROR_TYPE_ERROR,
145 "Failed to create indices: %s\n",
146 sqlite3_errmsg (dbh));
147}
148
149
150
151#if 0
152#define CHECK(a) GNUNET_break(a)
153#define ENULL NULL
154#else
155#define ENULL &e
156#define ENULL_DEFINED 1
157#define CHECK(a) if (! (a)) { GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", e); sqlite3_free(e); }
158#endif
159
160
161/**
162 * Initialize the database connections and associated
163 * data structures (create tables and indices
164 * as needed as well).
165 *
166 * @param plugin the plugin context (state for this module)
167 * @return #GNUNET_OK on success
168 */
169static int
170database_setup (struct Plugin *plugin)
171{
172 sqlite3_stmt *stmt;
173 char *afsdir;
174#if ENULL_DEFINED
175 char *e;
176#endif
177
178 if (GNUNET_OK !=
179 GNUNET_CONFIGURATION_get_value_filename (plugin->cfg,
180 "identity-provider-sqlite",
181 "FILENAME",
182 &afsdir))
183 {
184 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
185 "identity-provider-sqlite",
186 "FILENAME");
187 return GNUNET_SYSERR;
188 }
189 if (GNUNET_OK !=
190 GNUNET_DISK_file_test (afsdir))
191 {
192 if (GNUNET_OK !=
193 GNUNET_DISK_directory_create_for_file (afsdir))
194 {
195 GNUNET_break (0);
196 GNUNET_free (afsdir);
197 return GNUNET_SYSERR;
198 }
199 }
200 /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */
201 plugin->fn = afsdir;
202
203 /* Open database and precompile statements */
204 if (sqlite3_open (plugin->fn, &plugin->dbh) != SQLITE_OK)
205 {
206 LOG (GNUNET_ERROR_TYPE_ERROR,
207 _("Unable to initialize SQLite: %s.\n"),
208 sqlite3_errmsg (plugin->dbh));
209 return GNUNET_SYSERR;
210 }
211 CHECK (SQLITE_OK ==
212 sqlite3_exec (plugin->dbh,
213 "PRAGMA temp_store=MEMORY", NULL, NULL,
214 ENULL));
215 CHECK (SQLITE_OK ==
216 sqlite3_exec (plugin->dbh,
217 "PRAGMA synchronous=NORMAL", NULL, NULL,
218 ENULL));
219 CHECK (SQLITE_OK ==
220 sqlite3_exec (plugin->dbh,
221 "PRAGMA legacy_file_format=OFF", NULL, NULL,
222 ENULL));
223 CHECK (SQLITE_OK ==
224 sqlite3_exec (plugin->dbh,
225 "PRAGMA auto_vacuum=INCREMENTAL", NULL,
226 NULL, ENULL));
227 CHECK (SQLITE_OK ==
228 sqlite3_exec (plugin->dbh,
229 "PRAGMA encoding=\"UTF-8\"", NULL,
230 NULL, ENULL));
231 CHECK (SQLITE_OK ==
232 sqlite3_exec (plugin->dbh,
233 "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL,
234 ENULL));
235 CHECK (SQLITE_OK ==
236 sqlite3_exec (plugin->dbh,
237 "PRAGMA page_size=4092", NULL, NULL,
238 ENULL));
239
240 CHECK (SQLITE_OK ==
241 sqlite3_busy_timeout (plugin->dbh,
242 BUSY_TIMEOUT_MS));
243
244
245 /* Create table */
246 CHECK (SQLITE_OK ==
247 sq_prepare (plugin->dbh,
248 "SELECT 1 FROM sqlite_master WHERE tbl_name = 'identity001tickets'",
249 &stmt));
250 if ((sqlite3_step (stmt) == SQLITE_DONE) &&
251 (sqlite3_exec
252 (plugin->dbh,
253 "CREATE TABLE identity001tickets ("
254 " identity BLOB NOT NULL DEFAULT '',"
255 " audience BLOB NOT NULL DEFAULT '',"
256 " rnd INT8 NOT NULL DEFAULT '',"
257 " attributes BLOB NOT NULL DEFAULT ''"
258 ")",
259 NULL, NULL, NULL) != SQLITE_OK))
260 {
261 LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR,
262 "sqlite3_exec");
263 sqlite3_finalize (stmt);
264 return GNUNET_SYSERR;
265 }
266 sqlite3_finalize (stmt);
267
268 create_indices (plugin->dbh);
269
270 if ( (SQLITE_OK !=
271 sq_prepare (plugin->dbh,
272 "INSERT INTO identity001tickets (identity, audience, rnd, attributes)"
273 " VALUES (?, ?, ?, ?)",
274 &plugin->store_ticket)) ||
275 (SQLITE_OK !=
276 sq_prepare (plugin->dbh,
277 "DELETE FROM identity001tickets WHERE identity=? AND rnd=?",
278 &plugin->delete_ticket)) ||
279 (SQLITE_OK !=
280 sq_prepare (plugin->dbh,
281 "SELECT identity,audience,rnd,attributes"
282 " FROM identity001tickets WHERE identity=?"
283 " ORDER BY rnd LIMIT 1 OFFSET ?",
284 &plugin->iterate_tickets)) ||
285 (SQLITE_OK !=
286 sq_prepare (plugin->dbh,
287 "SELECT identity,audience,rnd,attributes"
288 " FROM identity001tickets WHERE audience=?"
289 " ORDER BY rnd LIMIT 1 OFFSET ?",
290 &plugin->iterate_tickets_by_audience)) )
291 {
292 LOG_SQLITE (plugin,
293 GNUNET_ERROR_TYPE_ERROR,
294 "precompiling");
295 return GNUNET_SYSERR;
296 }
297 return GNUNET_OK;
298}
299
300
301/**
302 * Shutdown database connection and associate data
303 * structures.
304 * @param plugin the plugin context (state for this module)
305 */
306static void
307database_shutdown (struct Plugin *plugin)
308{
309 int result;
310 sqlite3_stmt *stmt;
311
312 if (NULL != plugin->store_ticket)
313 sqlite3_finalize (plugin->store_ticket);
314 if (NULL != plugin->delete_ticket)
315 sqlite3_finalize (plugin->delete_ticket);
316 if (NULL != plugin->iterate_tickets)
317 sqlite3_finalize (plugin->iterate_tickets);
318 result = sqlite3_close (plugin->dbh);
319 if (result == SQLITE_BUSY)
320 {
321 LOG (GNUNET_ERROR_TYPE_WARNING,
322 _("Tried to close sqlite without finalizing all prepared statements.\n"));
323 stmt = sqlite3_next_stmt (plugin->dbh,
324 NULL);
325 while (NULL != stmt)
326 {
327 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
328 "sqlite",
329 "Closing statement %p\n",
330 stmt);
331 result = sqlite3_finalize (stmt);
332 if (result != SQLITE_OK)
333 GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
334 "sqlite",
335 "Failed to close statement %p: %d\n",
336 stmt,
337 result);
338 stmt = sqlite3_next_stmt (plugin->dbh,
339 NULL);
340 }
341 result = sqlite3_close (plugin->dbh);
342 }
343 if (SQLITE_OK != result)
344 LOG_SQLITE (plugin,
345 GNUNET_ERROR_TYPE_ERROR,
346 "sqlite3_close");
347
348 GNUNET_free_non_null (plugin->fn);
349}
350
351
352/**
353 * Store a ticket in the database.
354 *
355 * @param cls closure (internal context for the plugin)
356 * @param ticket the ticket to persist
357 * @param attrs attributes to persist
358 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
359 */
360static int
361identity_provider_sqlite_store_ticket (void *cls,
362 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
363 const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs)
364{
365 struct Plugin *plugin = cls;
366 int n;
367 size_t attrs_size;
368 char *attrs_serialized;
369
370 attrs_size = attribute_list_serialize_get_size (attrs);
371
372 attrs_serialized = GNUNET_malloc (attrs_size);
373
374 attribute_list_serialize (attrs,
375 attrs_serialized);
376
377 {
378 struct GNUNET_SQ_QueryParam sparams[] = {
379 GNUNET_SQ_query_param_auto_from_type (&ticket->identity),
380 GNUNET_SQ_query_param_auto_from_type (&ticket->audience),
381 GNUNET_SQ_query_param_uint64 (&ticket->rnd),
382 GNUNET_SQ_query_param_fixed_size (attrs_serialized, attrs_size),
383 GNUNET_SQ_query_param_end
384 };
385
386 if (GNUNET_OK !=
387 GNUNET_SQ_bind (plugin->store_ticket,
388 sparams))
389 {
390 LOG_SQLITE (plugin,
391 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
392 "sqlite3_bind_XXXX");
393 GNUNET_SQ_reset (plugin->dbh,
394 plugin->store_ticket);
395 return GNUNET_SYSERR;
396 }
397 n = sqlite3_step (plugin->store_ticket);
398 GNUNET_SQ_reset (plugin->dbh,
399 plugin->store_ticket);
400 }
401 switch (n)
402 {
403 case SQLITE_DONE:
404 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
405 "sqlite",
406 "Ticket stored\n");
407 return GNUNET_OK;
408 case SQLITE_BUSY:
409 LOG_SQLITE (plugin,
410 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
411 "sqlite3_step");
412 return GNUNET_NO;
413 default:
414 LOG_SQLITE (plugin,
415 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
416 "sqlite3_step");
417 return GNUNET_SYSERR;
418 }
419}
420
421
422/**
423 * Store a ticket in the database.
424 *
425 * @param cls closure (internal context for the plugin)
426 * @param ticket the ticket to delete
427 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
428 */
429static int
430identity_provider_sqlite_delete_ticket (void *cls,
431 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket)
432{
433 struct Plugin *plugin = cls;
434 int n;
435
436 {
437 struct GNUNET_SQ_QueryParam sparams[] = {
438 GNUNET_SQ_query_param_auto_from_type (&ticket->identity),
439 GNUNET_SQ_query_param_uint64 (&ticket->rnd),
440 GNUNET_SQ_query_param_end
441 };
442
443 if (GNUNET_OK !=
444 GNUNET_SQ_bind (plugin->delete_ticket,
445 sparams))
446 {
447 LOG_SQLITE (plugin,
448 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
449 "sqlite3_bind_XXXX");
450 GNUNET_SQ_reset (plugin->dbh,
451 plugin->store_ticket);
452 return GNUNET_SYSERR;
453 }
454 n = sqlite3_step (plugin->delete_ticket);
455 GNUNET_SQ_reset (plugin->dbh,
456 plugin->delete_ticket);
457 }
458 switch (n)
459 {
460 case SQLITE_DONE:
461 GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
462 "sqlite",
463 "Ticket deleted\n");
464 return GNUNET_OK;
465 case SQLITE_BUSY:
466 LOG_SQLITE (plugin,
467 GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK,
468 "sqlite3_step");
469 return GNUNET_NO;
470 default:
471 LOG_SQLITE (plugin,
472 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
473 "sqlite3_step");
474 return GNUNET_SYSERR;
475 }
476}
477
478
479/**
480 * The given 'sqlite' statement has been prepared to be run.
481 * It will return a record which should be given to the iterator.
482 * Runs the statement and parses the returned record.
483 *
484 * @param plugin plugin context
485 * @param stmt to run (and then clean up)
486 * @param iter iterator to call with the result
487 * @param iter_cls closure for @a iter
488 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
489 */
490static int
491get_ticket_and_call_iterator (struct Plugin *plugin,
492 sqlite3_stmt *stmt,
493 GNUNET_IDENTITY_PROVIDER_TicketIterator iter,
494 void *iter_cls)
495{
496 struct GNUNET_IDENTITY_PROVIDER_Ticket2 ticket;
497 size_t attrs_size;
498 void *attrs_serialized;
499 int ret;
500 int sret;
501
502 ret = GNUNET_NO;
503 if (SQLITE_ROW == (sret = sqlite3_step (stmt)))
504 {
505 struct GNUNET_SQ_ResultSpec rs[] = {
506 GNUNET_SQ_result_spec_auto_from_type (&ticket.identity),
507 GNUNET_SQ_result_spec_auto_from_type (&ticket.audience),
508 GNUNET_SQ_result_spec_uint64 (&ticket.rnd),
509 GNUNET_SQ_result_spec_variable_size (&attrs_serialized, &attrs_size),
510 GNUNET_SQ_result_spec_end
511
512 };
513 ret = GNUNET_SQ_extract_result (stmt,
514 rs);
515 if (GNUNET_OK != ret)
516 {
517 GNUNET_break (0);
518 ret = GNUNET_SYSERR;
519 }
520 else
521 {
522 struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs;
523
524 attrs = attribute_list_deserialize (attrs_serialized, attrs_size);
525
526 if (NULL == attrs)
527 {
528 GNUNET_break (0);
529 ret = GNUNET_SYSERR;
530 }
531 else
532 {
533 if (NULL != iter)
534 iter (iter_cls,
535 &ticket,
536 attrs);
537 ret = GNUNET_YES;
538 }
539 }
540 GNUNET_SQ_cleanup_result (rs);
541 }
542 else
543 {
544 if (SQLITE_DONE != sret)
545 LOG_SQLITE (plugin,
546 GNUNET_ERROR_TYPE_ERROR,
547 "sqlite_step");
548 }
549 GNUNET_SQ_reset (plugin->dbh,
550 stmt);
551 return ret;
552}
553
554/**
555 * Iterate over the results for a particular key and zone in the
556 * datastore. Will return at most one result to the iterator.
557 *
558 * @param cls closure (internal context for the plugin)
559 * @param identity the issuing identity or audience (depending on audience switch)
560 * @param audience GNUNET_YES if identity is audience
561 * @param offset offset in the list of all matching records
562 * @param iter function to call with the result
563 * @param iter_cls closure for @a iter
564 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
565 */
566static int
567identity_provider_sqlite_iterate_tickets (void *cls,
568 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
569 int audience,
570 uint64_t offset,
571 GNUNET_IDENTITY_PROVIDER_TicketIterator iter,
572 void *iter_cls)
573{
574 struct Plugin *plugin = cls;
575 sqlite3_stmt *stmt;
576 int err;
577
578 if (NULL == identity)
579 {
580 GNUNET_break (0);
581 return GNUNET_SYSERR;
582 }
583 struct GNUNET_SQ_QueryParam params[] = {
584 GNUNET_SQ_query_param_auto_from_type (identity),
585 GNUNET_SQ_query_param_uint64 (&offset),
586 GNUNET_SQ_query_param_end
587 };
588 if (GNUNET_YES == audience)
589 {
590 stmt = plugin->iterate_tickets_by_audience;
591 err = GNUNET_SQ_bind (stmt,
592 params);
593 }
594 else
595 {
596 stmt = plugin->iterate_tickets;
597 err = GNUNET_SQ_bind (stmt,
598 params);
599 }
600 if (GNUNET_OK != err)
601 {
602 LOG_SQLITE (plugin,
603 GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
604 "sqlite3_bind_XXXX");
605 GNUNET_SQ_reset (plugin->dbh,
606 stmt);
607 return GNUNET_SYSERR;
608 }
609 return get_ticket_and_call_iterator (plugin,
610 stmt,
611 iter,
612 iter_cls);
613}
614
615
616/**
617 * Entry point for the plugin.
618 *
619 * @param cls the "struct GNUNET_IDENTITY_PROVIDER_PluginEnvironment*"
620 * @return NULL on error, otherwise the plugin context
621 */
622void *
623libgnunet_plugin_identity_provider_sqlite_init (void *cls)
624{
625 static struct Plugin plugin;
626 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
627 struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *api;
628
629 if (NULL != plugin.cfg)
630 return NULL; /* can only initialize once! */
631 memset (&plugin, 0, sizeof (struct Plugin));
632 plugin.cfg = cfg;
633 if (GNUNET_OK != database_setup (&plugin))
634 {
635 database_shutdown (&plugin);
636 return NULL;
637 }
638 api = GNUNET_new (struct GNUNET_IDENTITY_PROVIDER_PluginFunctions);
639 api->cls = &plugin;
640 api->store_ticket = &identity_provider_sqlite_store_ticket;
641 api->delete_ticket = &identity_provider_sqlite_delete_ticket;
642 api->iterate_tickets = &identity_provider_sqlite_iterate_tickets;
643 LOG (GNUNET_ERROR_TYPE_INFO,
644 _("Sqlite database running\n"));
645 return api;
646}
647
648
649/**
650 * Exit point from the plugin.
651 *
652 * @param cls the plugin context (as returned by "init")
653 * @return always NULL
654 */
655void *
656libgnunet_plugin_namestore_sqlite_done (void *cls)
657{
658 struct GNUNET_IDENTITY_PROVIDER_PluginFunctions *api = cls;
659 struct Plugin *plugin = api->cls;
660
661 database_shutdown (plugin);
662 plugin->cfg = NULL;
663 GNUNET_free (api);
664 LOG (GNUNET_ERROR_TYPE_DEBUG,
665 "sqlite plugin is finished\n");
666 return NULL;
667}
668
669/* end of plugin_identity_provider_sqlite.c */
diff --git a/src/include/gnunet_identity_provider_plugin.h b/src/include/gnunet_identity_provider_plugin.h
new file mode 100644
index 000000000..5867a5b80
--- /dev/null
+++ b/src/include/gnunet_identity_provider_plugin.h
@@ -0,0 +1,123 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2013 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/**
22 * @author Martin Schanzenbach
23 *
24 * @file
25 * Plugin API for the idp database backend
26 *
27 * @defgroup identity-provider-plugin IdP service plugin API
28 * Plugin API for the idp database backend
29 * @{
30 */
31#ifndef GNUNET_IDENTITY_PROVIDER_PLUGIN_H
32#define GNUNET_IDENTITY_PROVIDER_PLUGIN_H
33
34#include "gnunet_util_lib.h"
35#include "gnunet_identity_provider_service.h"
36
37#ifdef __cplusplus
38extern "C"
39{
40#if 0 /* keep Emacsens' auto-indent happy */
41}
42#endif
43#endif
44
45
46/**
47 * Function called by for each matching ticket.
48 *
49 * @param cls closure
50 * @param ticket the ticket
51 * @prarm attrs the attributes
52 */
53typedef void (*GNUNET_IDENTITY_PROVIDER_TicketIterator) (void *cls,
54 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
55 const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
56
57
58/**
59 * @brief struct returned by the initialization function of the plugin
60 */
61struct GNUNET_IDENTITY_PROVIDER_PluginFunctions
62{
63
64 /**
65 * Closure to pass to all plugin functions.
66 */
67 void *cls;
68
69 /**
70 * Store a ticket in the database.
71 *
72 * @param cls closure (internal context for the plugin)
73 * @param ticket the ticket to store
74 * @param attrs the attributes shared with the ticket
75 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
76 */
77 int (*store_ticket) (void *cls,
78 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
79 const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
80
81 /**
82 * Delete a ticket from the database.
83 *
84 * @param cls closure (internal context for the plugin)
85 * @param ticket the ticket to store
86 * @return #GNUNET_OK on success, else #GNUNET_SYSERR
87 */
88 int (*delete_ticket) (void *cls,
89 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket);
90
91
92
93 /**
94 * Iterate over all tickets
95 *
96 * @param cls closure (internal context for the plugin)
97 * @param identity the identity
98 * @param audience GNUNET_YES if the identity is the audience of the ticket
99 * else it is considered the issuer
100 * @param iter function to call with the result
101 * @param iter_cls closure for @a iter
102 * @return #GNUNET_OK on success, #GNUNET_NO if there were no results, #GNUNET_SYSERR on error
103 */
104 int (*iterate_tickets) (void *cls,
105 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
106 int audience,
107 uint64_t offset,
108 GNUNET_IDENTITY_PROVIDER_TicketIterator iter, void *iter_cls);
109
110
111};
112
113
114#if 0 /* keep Emacsens' auto-indent happy */
115{
116#endif
117#ifdef __cplusplus
118}
119#endif
120
121#endif
122
123/** @} */ /* end of group */
diff --git a/src/include/gnunet_identity_provider_service.h b/src/include/gnunet_identity_provider_service.h
index 049f891cc..02cd15959 100644
--- a/src/include/gnunet_identity_provider_service.h
+++ b/src/include/gnunet_identity_provider_service.h
@@ -336,17 +336,25 @@ GNUNET_IDENTITY_PROVIDER_get_attributes_stop (struct GNUNET_IDENTITY_PROVIDER_At
336 * token 336 * token
337 * 337 *
338 * @param cls closure 338 * @param cls closure
339 * @param grant the label in GNS pointing to the token
340 * @param ticket the ticket 339 * @param ticket the ticket
341 * @param token the issued token
342 * @param name name assigned by the user for this ego,
343 * NULL if the user just deleted the ego and it
344 * must thus no longer be used
345 */ 340 */
346typedef void 341typedef void
347(*GNUNET_IDENTITY_PROVIDER_TicketCallback)(void *cls, 342(*GNUNET_IDENTITY_PROVIDER_TicketCallback)(void *cls,
348 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket); 343 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket);
349 344
345/**
346 * Method called when issued tickets are retrieved. Also returns the attributes
347 * that were issued at the time.
348 *
349 * @param cls closure
350 * @param ticket the ticket
351 * @param attrs the attributes as list
352 */
353typedef void
354(*GNUNET_IDENTITY_PROVIDER_TicketResult)(void *cls,
355 const struct GNUNET_IDENTITY_PROVIDER_Ticket2 *ticket,
356 const struct GNUNET_IDENTITY_PROVIDER_AttributeList *attrs);
357
350 358
351/** 359/**
352 * Issues a ticket to another identity. The identity may use 360 * Issues a ticket to another identity. The identity may use
@@ -389,7 +397,7 @@ GNUNET_IDENTITY_PROVIDER_idp_ticket_revoke (struct GNUNET_IDENTITY_PROVIDER_Hand
389 397
390 398
391 399
392/** TODO 400/**
393 * Consumes an issued ticket. The ticket is persisted 401 * Consumes an issued ticket. The ticket is persisted
394 * and used to retrieve identity information from the issuer 402 * and used to retrieve identity information from the issuer
395 * 403 *
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 63afeba8d..743a28946 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -2646,6 +2646,12 @@ extern "C"
2646 2646
2647#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET 973 2647#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_CONSUME_TICKET 973
2648 2648
2649#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_START 974
2650
2651#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_STOP 975
2652
2653#define GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_TICKET_ITERATION_NEXT 976
2654
2649/************************************************** 2655/**************************************************
2650 * 2656 *
2651 * CREDENTIAL MESSAGE TYPES 2657 * CREDENTIAL MESSAGE TYPES