f3a6e2073270ef4253221be58c22398fb281eefe
[oweals/gnunet.git] / src / reclaim / gnunet-service-reclaim.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2012-2015 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your 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    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18    SPDX-License-Identifier: AGPL3.0-or-later
19    */
20 /**
21  * @author Martin Schanzenbach
22  * @file src/reclaim/gnunet-service-reclaim.c
23  * @brief reclaim Service
24  *
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_identity_service.h"
31 #include "gnunet_gnsrecord_lib.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_credential_service.h"
34 #include "gnunet_statistics_service.h"
35 #include "gnunet_gns_service.h"
36 #include "gnunet_reclaim_plugin.h"
37 #include "gnunet_reclaim_attribute_lib.h"
38 #include "gnunet_signatures.h"
39 #include "reclaim.h"
40
41 /**
42  * First pass state
43  */
44 #define STATE_INIT 0
45
46 /**
47  * Normal operation state
48  */
49 #define STATE_POST_INIT 1
50
51 /**
52  * Minimum interval between updates
53  */
54 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
55
56 /**
57  * Standard token expiration time
58  */
59 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
60
61 /**
62  * Identity handle
63  */
64 static struct GNUNET_IDENTITY_Handle *identity_handle;
65
66 /**
67  * Database handle
68  */
69 static struct GNUNET_RECLAIM_PluginFunctions *TKT_database;
70
71 /**
72  * Name of DB plugin
73  */
74 static char *db_lib_name;
75
76 /**
77  * Token expiration interval
78  */
79 static struct GNUNET_TIME_Relative token_expiration_interval;
80
81 /**
82  * Namestore handle
83  */
84 static struct GNUNET_NAMESTORE_Handle *nsh;
85
86 /**
87  * GNS handle
88  */
89 static struct GNUNET_GNS_Handle *gns_handle;
90
91 /**
92  * Credential handle
93  */
94 static struct GNUNET_CREDENTIAL_Handle *credential_handle;
95
96 /**
97  * Namestore qe
98  */
99 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
100
101 /**
102  * Namestore iterator
103  */
104 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
105
106 /**
107  * Timeout task
108  */
109 static struct GNUNET_SCHEDULER_Task *timeout_task;
110
111 /**
112  * Update task
113  */
114 static struct GNUNET_SCHEDULER_Task *update_task;
115
116
117 /**
118  * Handle to the statistics service.
119  */
120 static struct GNUNET_STATISTICS_Handle *stats;
121
122 /**
123  * Our configuration.
124  */
125 static const struct GNUNET_CONFIGURATION_Handle *cfg;
126
127 /**
128  * An idp client
129  */
130 struct IdpClient;
131
132 /**
133  * A ticket iteration operation.
134  */
135 struct TicketIteration
136 {
137   /**
138    * DLL
139    */
140   struct TicketIteration *next;
141
142   /**
143    * DLL
144    */
145   struct TicketIteration *prev;
146
147   /**
148    * Client which intiated this zone iteration
149    */
150   struct IdpClient *client;
151
152   /**
153    * Key of the identity we are iterating over.
154    */
155   struct GNUNET_CRYPTO_EcdsaPublicKey identity;
156
157   /**
158    * Identity is audience
159    */
160   uint32_t is_audience;
161
162   /**
163    * The operation id fot the iteration in the response for the client
164    */
165   uint32_t r_id;
166
167   /**
168    * Offset of the iteration used to address next result of the
169    * iteration in the store
170    *
171    * Initialy set to 0 in handle_iteration_start
172    * Incremented with by every call to handle_iteration_next
173    */
174   uint32_t offset;
175
176 };
177
178
179 /**
180  * An attribute iteration operation.
181  */
182 struct AttributeIterator
183 {
184   /**
185    * Next element in the DLL
186    */
187   struct AttributeIterator *next;
188
189   /**
190    * Previous element in the DLL
191    */
192   struct AttributeIterator *prev;
193
194   /**
195    * IDP client which intiated this zone iteration
196    */
197   struct IdpClient *client;
198
199   /**
200    * Key of the zone we are iterating over.
201    */
202   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
203
204   /**
205    * Namestore iterator
206    */
207   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
208
209   /**
210    * The operation id fot the zone iteration in the response for the client
211    */
212   uint32_t request_id;
213
214 };
215
216
217
218 /**
219  * An idp client
220  */
221 struct IdpClient
222 {
223
224   /**
225    * The client
226    */
227   struct GNUNET_SERVICE_Client *client;
228
229   /**
230    * Message queue for transmission to @e client
231    */
232   struct GNUNET_MQ_Handle *mq;
233
234   /**
235    * Head of the DLL of
236    * Attribute iteration operations in
237    * progress initiated by this client
238    */
239   struct AttributeIterator *attr_iter_head;
240
241   /**
242    * Tail of the DLL of
243    * Attribute iteration operations
244    * in progress initiated by this client
245    */
246   struct AttributeIterator *attr_iter_tail;
247
248   /**
249    * Head of DLL of ticket iteration ops
250    */
251   struct TicketIteration *ticket_iter_head;
252
253   /**
254    * Tail of DLL of ticket iteration ops
255    */
256   struct TicketIteration *ticket_iter_tail;
257
258   /**
259    * Head of DLL of ticket revocation ops
260    */
261   struct TicketRevocationHandle *revoke_op_head;
262
263   /**
264    * Tail of DLL of ticket revocation ops
265    */
266   struct TicketRevocationHandle *revoke_op_tail;
267
268   /**
269    * Head of DLL of ticket issue ops
270    */
271   struct TicketIssueHandle *issue_op_head;
272
273   /**
274    * Tail of DLL of ticket issue ops
275    */
276   struct TicketIssueHandle *issue_op_tail;
277
278   /**
279    * Head of DLL of ticket consume ops
280    */
281   struct ConsumeTicketHandle *consume_op_head;
282
283   /**
284    * Tail of DLL of ticket consume ops
285    */
286   struct ConsumeTicketHandle *consume_op_tail;
287
288   /**
289    * Head of DLL of attribute store ops
290    */
291   struct AttributeStoreHandle *store_op_head;
292
293   /**
294    * Tail of DLL of attribute store ops
295    */
296   struct AttributeStoreHandle *store_op_tail;
297
298 };
299
300 struct AttributeStoreHandle
301 {
302   /**
303    * DLL
304    */
305   struct AttributeStoreHandle *next;
306
307   /**
308    * DLL
309    */
310   struct AttributeStoreHandle *prev;
311
312   /**
313    * Client connection
314    */
315   struct IdpClient *client;
316
317   /**
318    * Identity
319    */
320   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
321
322   /**
323    * Identity pubkey
324    */
325   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
326
327   /**
328    * QueueEntry
329    */
330   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
331
332   /**
333    * The attribute to store
334    */
335   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
336
337   /**
338    * The attribute expiration interval
339    */
340   struct GNUNET_TIME_Relative exp;
341
342   /**
343    * request id
344    */
345   uint32_t r_id;
346 };
347
348
349 /* Prototype */
350 struct ParallelLookup;
351
352 struct ConsumeTicketHandle
353 {
354   /**
355    * DLL
356    */
357   struct ConsumeTicketHandle *next;
358
359   /**
360    * DLL
361    */
362   struct ConsumeTicketHandle *prev;
363
364   /**
365    * Client connection
366    */
367   struct IdpClient *client;
368
369   /**
370    * Ticket
371    */
372   struct GNUNET_RECLAIM_Ticket ticket;
373
374   /**
375    * LookupRequest
376    */
377   struct GNUNET_GNS_LookupRequest *lookup_request;
378
379   /**
380    * Audience Key
381    */
382   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
383
384   /**
385    * Audience Key
386    */
387   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
388
389   /**
390    * Lookup DLL
391    */
392   struct ParallelLookup *parallel_lookups_head;
393
394   /**
395    * Lookup DLL
396    */
397   struct ParallelLookup *parallel_lookups_tail;
398
399   /**
400    * Kill task
401    */
402   struct GNUNET_SCHEDULER_Task *kill_task;
403
404   /**
405    * Attributes
406    */
407   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
408
409   /**
410    * Lookup time
411    */
412   struct GNUNET_TIME_Absolute lookup_start_time;
413
414   /**
415    * request id
416    */
417   uint32_t r_id;
418 };
419
420 /**
421  * Handle for a parallel GNS lookup job
422  */
423 struct ParallelLookup
424 {
425   /* DLL */
426   struct ParallelLookup *next;
427
428   /* DLL */
429   struct ParallelLookup *prev;
430
431   /* The GNS request */
432   struct GNUNET_GNS_LookupRequest *lookup_request;
433
434   /* The handle the return to */
435   struct ConsumeTicketHandle *handle;
436
437   /**
438    * Lookup time
439    */
440   struct GNUNET_TIME_Absolute lookup_start_time;
441
442   /* The label to look up */
443   char *label;
444 };
445
446 /**
447  * Updated attribute IDs
448  */
449 struct TicketAttributeUpdateEntry
450 {
451   /**
452    * DLL
453    */
454   struct TicketAttributeUpdateEntry *next;
455
456   /**
457    * DLL
458    */
459   struct TicketAttributeUpdateEntry *prev;
460
461   /**
462    * The old ID
463    */
464   uint64_t old_id;
465
466   /**
467    * The new ID
468    */
469   uint64_t new_id;
470 };
471
472 /**
473  * Ticket revocation request handle
474  */
475 struct TicketRevocationHandle
476 {
477   /**
478    * DLL
479    */
480   struct TicketRevocationHandle *prev;
481
482   /**
483    * DLL
484    */
485   struct TicketRevocationHandle *next;
486
487   /**
488    * Attribute updates
489    */
490   struct TicketAttributeUpdateEntry *attr_updates_head;
491
492   /**
493    * Attribute updates
494    */
495   struct TicketAttributeUpdateEntry *attr_updates_tail;
496
497   /**
498    * Client connection
499    */
500   struct IdpClient *client;
501
502   /**
503    * Attributes to reissue
504    */
505   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
506
507   /**
508    * Attributes to revoke
509    */
510   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *rvk_attrs;
511
512   /**
513    * Issuer Key
514    */
515   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
516
517   /**
518    * Ticket to issue
519    */
520   struct GNUNET_RECLAIM_Ticket ticket;
521
522   /**
523    * QueueEntry
524    */
525   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
526
527   /**
528    * Namestore iterator
529    */
530   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
531
532   /**
533    * Offset
534    */
535   uint32_t offset;
536
537   /**
538    * request id
539    */
540   uint32_t r_id;
541 };
542
543
544
545 /**
546  * Ticket issue request handle
547  */
548 struct TicketIssueHandle
549 {
550   /**
551    * DLL
552    */
553   struct TicketIssueHandle *prev;
554
555   /**
556    * DLL
557    */
558   struct TicketIssueHandle *next;
559
560   /**
561    * Client connection
562    */
563   struct IdpClient *client;
564
565   /**
566    * Attributes to issue
567    */
568   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
569
570   /**
571    * Issuer Key
572    */
573   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
574
575   /**
576    * Ticket to issue
577    */
578   struct GNUNET_RECLAIM_Ticket ticket;
579
580   /**
581    * QueueEntry
582    */
583   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
584
585   /**
586    * request id
587    */
588   uint32_t r_id;
589 };
590
591
592 /**
593  * DLL for ego handles to egos containing the RECLAIM_ATTRS in a
594  * map in json_t format
595  *
596  */
597 struct EgoEntry
598 {
599   /**
600    * DLL
601    */
602   struct EgoEntry *next;
603
604   /**
605    * DLL
606    */
607   struct EgoEntry *prev;
608
609   /**
610    * Ego handle
611    */
612   struct GNUNET_IDENTITY_Ego *ego;
613
614   /**
615    * Attribute map. Contains the attributes as json_t
616    */
617   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
618
619 };
620
621 /**
622  * Cleanup task
623  */
624 static void
625 cleanup()
626 {
627   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
628               "Cleaning up\n");
629
630   if (NULL != stats)
631   {
632     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
633     stats = NULL;
634   }
635   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name,
636                                               TKT_database));
637   GNUNET_free (db_lib_name);
638   db_lib_name = NULL;
639   if (NULL != timeout_task)
640     GNUNET_SCHEDULER_cancel (timeout_task);
641   if (NULL != update_task)
642     GNUNET_SCHEDULER_cancel (update_task);
643   if (NULL != identity_handle)
644     GNUNET_IDENTITY_disconnect (identity_handle);
645   if (NULL != gns_handle)
646     GNUNET_GNS_disconnect (gns_handle);
647   if (NULL != credential_handle)
648     GNUNET_CREDENTIAL_disconnect (credential_handle);
649   if (NULL != ns_it)
650     GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
651   if (NULL != ns_qe)
652     GNUNET_NAMESTORE_cancel (ns_qe);
653   if (NULL != nsh)
654     GNUNET_NAMESTORE_disconnect (nsh);
655 }
656
657 /**
658  * Shutdown task
659  *
660  * @param cls NULL
661  */
662 static void
663 do_shutdown (void *cls)
664 {
665   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
666               "Shutting down...\n");
667   cleanup();
668 }
669
670
671 static int
672 create_sym_key_from_ecdh (const struct GNUNET_HashCode *new_key_hash,
673                           struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
674                           struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
675 {
676   struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
677
678   GNUNET_CRYPTO_hash_to_enc (new_key_hash,
679                              &new_key_hash_str);
680   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
681   static const char ctx_key[] = "gnuid-aes-ctx-key";
682   GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
683                      new_key_hash, sizeof (struct GNUNET_HashCode),
684                      ctx_key, strlen (ctx_key),
685                      NULL, 0);
686   static const char ctx_iv[] = "gnuid-aes-ctx-iv";
687   GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
688                      new_key_hash, sizeof (struct GNUNET_HashCode),
689                      ctx_iv, strlen (ctx_iv),
690                      NULL, 0);
691   return GNUNET_OK;
692 }
693
694 /**
695  * Cleanup ticket consume handle
696  * @param handle the handle to clean up
697  */
698 static void
699 cleanup_ticket_issue_handle (struct TicketIssueHandle *handle)
700 {
701   if (NULL != handle->attrs)
702     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs);
703   if (NULL != handle->ns_qe)
704     GNUNET_NAMESTORE_cancel (handle->ns_qe);
705   GNUNET_free (handle);
706 }
707
708
709 static void
710 send_ticket_result (struct IdpClient *client,
711                     uint32_t r_id,
712                     const struct GNUNET_RECLAIM_Ticket *ticket,
713                     const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
714 {
715   struct TicketResultMessage *irm;
716   struct GNUNET_MQ_Envelope *env;
717   struct GNUNET_RECLAIM_Ticket *ticket_buf;
718
719   /* store ticket in DB */
720   if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls,
721                                                ticket,
722                                                attrs))
723   {
724     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
725                 "Unable to store ticket after issue\n");
726     GNUNET_break (0);
727   }
728
729   env = GNUNET_MQ_msg_extra (irm,
730                              sizeof (struct GNUNET_RECLAIM_Ticket),
731                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
732   ticket_buf = (struct GNUNET_RECLAIM_Ticket *)&irm[1];
733   *ticket_buf = *ticket;
734   irm->id = htonl (r_id);
735   GNUNET_MQ_send (client->mq,
736                   env);
737 }
738
739 static void
740 store_ticket_issue_cont (void *cls,
741                          int32_t success,
742                          const char *emsg)
743 {
744   struct TicketIssueHandle *handle = cls;
745
746   handle->ns_qe = NULL;
747   GNUNET_CONTAINER_DLL_remove (handle->client->issue_op_head,
748                                handle->client->issue_op_tail,
749                                handle);
750   if (GNUNET_SYSERR == success)
751   {
752     cleanup_ticket_issue_handle (handle);
753     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
754                 "Unknown Error\n");
755     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
756     return;
757   }
758   send_ticket_result (handle->client,
759                       handle->r_id,
760                       &handle->ticket,
761                       handle->attrs);
762   cleanup_ticket_issue_handle (handle);
763 }
764
765
766 static int
767 serialize_authz_record (const struct GNUNET_RECLAIM_Ticket *ticket,
768                          const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
769                          struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
770                          char **result)
771 {
772   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
773   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
774   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
775   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
776   struct GNUNET_HashCode new_key_hash;
777   ssize_t enc_size;
778   char *enc_keyinfo;
779   char *buf;
780   char *write_ptr;
781   char attrs_str_len;
782   char* label;
783
784   GNUNET_assert (NULL != attrs->list_head);
785   attrs_str_len = 0;
786   for (le = attrs->list_head; NULL != le; le = le->next) {
787     attrs_str_len += 15 + 1; //TODO propery calculate
788   }
789   buf = GNUNET_malloc (attrs_str_len);
790   write_ptr = buf;
791   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
792               "Writing attributes\n");
793   for (le = attrs->list_head; NULL != le; le = le->next) {
794     label = GNUNET_STRINGS_data_to_string_alloc (&le->claim->id,
795                                                  sizeof (uint64_t));
796     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
797                 "Adding attribute to record: %s\n", label);
798
799     GNUNET_memcpy (write_ptr,
800                    label,
801                    strlen (label));
802     write_ptr[strlen (label)] = ',';
803     write_ptr += strlen (label) + 1;
804     GNUNET_free (label);
805   }
806   write_ptr--;
807   write_ptr[0] = '\0'; //replace last , with a 0-terminator
808   // ECDH keypair E = eG
809   *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
810   GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
811                                       &ecdh_pubkey);
812   enc_keyinfo = GNUNET_malloc (attrs_str_len);
813   // Derived key K = H(eB)
814   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
815                                                         &ticket->audience,
816                                                         &new_key_hash));
817   create_sym_key_from_ecdh (&new_key_hash, &skey, &iv);
818   enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf,
819                                               attrs_str_len,
820                                               &skey, &iv,
821                                               enc_keyinfo);
822   *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+
823                            enc_size);
824   GNUNET_memcpy (*result,
825                  &ecdh_pubkey,
826                  sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
827   GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
828                  enc_keyinfo,
829                  enc_size);
830   GNUNET_free (enc_keyinfo);
831   GNUNET_free (buf);
832   return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size;
833 }
834
835
836
837 static void
838 issue_ticket (struct TicketIssueHandle *ih)
839 {
840   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
841   struct GNUNET_GNSRECORD_Data code_record[1];
842   char *authz_record_data;
843   size_t authz_record_len;
844   char *label;
845
846   //TODO rename function
847   authz_record_len = serialize_authz_record (&ih->ticket,
848                                              ih->attrs,
849                                              &ecdhe_privkey,
850                                              &authz_record_data);
851   code_record[0].data = authz_record_data;
852   code_record[0].data_size = authz_record_len;
853   code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
854   code_record[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_AUTHZ;
855   code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
856
857   label = GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd,
858                                                sizeof (uint64_t));
859   //Publish record
860   ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
861                                               &ih->identity,
862                                               label,
863                                               1,
864                                               code_record,
865                                               &store_ticket_issue_cont,
866                                               ih);
867   GNUNET_free (ecdhe_privkey);
868   GNUNET_free (label);
869   GNUNET_free (authz_record_data);
870 }
871
872
873 static int
874 check_issue_ticket_message(void *cls,
875                            const struct IssueTicketMessage *im)
876 {
877   uint16_t size;
878
879   size = ntohs (im->header.size);
880   if (size <= sizeof (struct IssueTicketMessage))
881   {
882     GNUNET_break (0);
883     return GNUNET_SYSERR;
884   }
885   return GNUNET_OK;
886 }
887
888
889 static void
890 handle_issue_ticket_message (void *cls,
891                              const struct IssueTicketMessage *im)
892 {
893   struct TicketIssueHandle *ih;
894   struct IdpClient *idp = cls;
895   size_t attrs_len;
896
897   ih = GNUNET_new (struct TicketIssueHandle);
898   attrs_len = ntohs (im->attr_len);
899   ih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char*)&im[1], attrs_len);
900   ih->r_id = ntohl (im->id);
901   ih->client = idp;
902   ih->identity = im->identity;
903   GNUNET_CRYPTO_ecdsa_key_get_public (&ih->identity,
904                                       &ih->ticket.identity);
905   ih->ticket.audience = im->rp;
906   ih->ticket.rnd =
907     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
908                               UINT64_MAX);
909   GNUNET_CONTAINER_DLL_insert (idp->issue_op_head,
910                                idp->issue_op_tail,
911                                ih);
912   issue_ticket (ih);
913   GNUNET_SERVICE_client_continue (idp->client);
914
915 }
916
917 /**********************************************************
918  * Revocation
919  **********************************************************/
920
921 /**
922  * Cleanup revoke handle
923  *
924  * @param rh the ticket revocation handle
925  */
926 static void
927 cleanup_revoke_ticket_handle (struct TicketRevocationHandle *rh)
928 {
929   if (NULL != rh->attrs)
930     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->attrs);
931   if (NULL != rh->rvk_attrs)
932     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->rvk_attrs);
933   if (NULL != rh->ns_qe)
934     GNUNET_NAMESTORE_cancel (rh->ns_qe);
935   if (NULL != rh->ns_it)
936     GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
937   GNUNET_free (rh);
938 }
939
940
941 /**
942  * Send revocation result
943  *
944  * @param rh ticket revocation handle
945  * @param success GNUNET_OK if successful result
946  */
947 static void
948 send_revocation_finished (struct TicketRevocationHandle *rh,
949                           uint32_t success)
950 {
951   struct GNUNET_MQ_Envelope *env;
952   struct RevokeTicketResultMessage *trm;
953
954   GNUNET_break(TKT_database->delete_ticket (TKT_database->cls,
955                                             &rh->ticket));
956
957   env = GNUNET_MQ_msg (trm,
958                        GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
959   trm->id = htonl (rh->r_id);
960   trm->success = htonl (success);
961   GNUNET_MQ_send (rh->client->mq,
962                   env);
963   GNUNET_CONTAINER_DLL_remove (rh->client->revoke_op_head,
964                                rh->client->revoke_op_tail,
965                                rh);
966 }
967
968
969 /**
970  * Process ticket from database
971  *
972  * @param cls struct TicketIterationProcResult
973  * @param ticket the ticket
974  * @param attrs the attributes
975  */
976 static void
977 ticket_reissue_proc (void *cls,
978                      const struct GNUNET_RECLAIM_Ticket *ticket,
979                      const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs);
980
981 static void
982 revocation_reissue_tickets (struct TicketRevocationHandle *rh);
983
984
985 static void reissue_next (void *cls)
986 {
987   struct TicketRevocationHandle *rh = cls;
988   revocation_reissue_tickets (rh);
989 }
990
991
992 static void
993 reissue_ticket_cont (void *cls,
994                      int32_t success,
995                      const char *emsg)
996 {
997   struct TicketRevocationHandle *rh = cls;
998
999   rh->ns_qe = NULL;
1000   if (GNUNET_SYSERR == success)
1001   {
1002     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
1003                 "Unknown Error\n");
1004     send_revocation_finished (rh, GNUNET_SYSERR);
1005     cleanup_revoke_ticket_handle (rh);
1006     return;
1007   }
1008   rh->offset++;
1009   GNUNET_SCHEDULER_add_now (&reissue_next, rh);
1010 }
1011
1012
1013 /**
1014  * Process ticket from database
1015  *
1016  * @param cls struct TicketIterationProcResult
1017  * @param ticket the ticket
1018  * @param attrs the attributes
1019  */
1020 static void
1021 ticket_reissue_proc (void *cls,
1022                      const struct GNUNET_RECLAIM_Ticket *ticket,
1023                      const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
1024 {
1025   struct TicketRevocationHandle *rh = cls;
1026   struct TicketAttributeUpdateEntry *tue;
1027   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1028   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1029   struct GNUNET_GNSRECORD_Data code_record[1];
1030   int reissue_ticket;
1031   size_t authz_record_len;
1032   char *authz_record_data;
1033   char *label;
1034
1035
1036   if (NULL == ticket)
1037   {
1038     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1039                 "Iteration done\n");
1040     return;
1041   }
1042
1043   if (0 == memcmp (&ticket->audience,
1044                    &rh->ticket.audience,
1045                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1046   {
1047     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1048                 "Do not reissue for this identity.!\n");
1049     label = GNUNET_STRINGS_data_to_string_alloc (&rh->ticket.rnd,
1050                                                  sizeof (uint64_t));
1051     //Delete record
1052     rh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1053                                                 &rh->identity,
1054                                                 label,
1055                                                 0,
1056                                                 NULL,
1057                                                 &reissue_ticket_cont,
1058                                                 rh);
1059
1060     GNUNET_free (label);
1061     return;
1062   }
1063
1064   /*
1065    * Check if any attribute of this ticket intersects with a rollover attribute
1066    */
1067   reissue_ticket = GNUNET_NO;
1068   for (le = attrs->list_head; NULL != le; le = le->next)
1069   {
1070     for (tue = rh->attr_updates_head;
1071          NULL != tue;
1072          tue = tue->next)
1073     {
1074       if (tue->old_id == le->claim->id)
1075       {
1076         reissue_ticket = GNUNET_YES;
1077         le->claim->id = tue->new_id;
1078       }
1079     }
1080   }
1081
1082   if (GNUNET_NO == reissue_ticket)
1083   {
1084     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1085                 "Skipping ticket.\n");
1086
1087     rh->offset++;
1088     GNUNET_SCHEDULER_add_now (&reissue_next, rh);
1089
1090
1091     return;
1092   }
1093
1094   //Create new ABE key for RP
1095
1096   /* If this is the RP we want to revoke attributes of, the do so */
1097
1098   //TODO rename function
1099   authz_record_len = serialize_authz_record (ticket,
1100                                              attrs,
1101                                              &ecdhe_privkey,
1102                                              &authz_record_data);
1103   code_record[0].data = authz_record_data;
1104   code_record[0].data_size = authz_record_len;
1105   code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
1106   code_record[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_AUTHZ;
1107   code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1108
1109   label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
1110                                                sizeof (uint64_t));
1111   //Publish record
1112   rh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1113                                               &rh->identity,
1114                                               label,
1115                                               1,
1116                                               code_record,
1117                                               &reissue_ticket_cont,
1118                                               rh);
1119   GNUNET_free (ecdhe_privkey);
1120   GNUNET_free (label);
1121   GNUNET_free (authz_record_data);
1122 }
1123
1124
1125 /* Prototype for below function */
1126 static void
1127 attr_reenc_cont (void *cls,
1128                  int32_t success,
1129                  const char *emsg);
1130
1131 static void
1132 revocation_reissue_tickets (struct TicketRevocationHandle *rh)
1133 {
1134   int ret;
1135   /* Done, issue new keys */
1136   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137               "Revocation Phase III: Reissuing Tickets\n");
1138   if (GNUNET_SYSERR == (ret = TKT_database->iterate_tickets (TKT_database->cls,
1139                                                              &rh->ticket.identity,
1140                                                              GNUNET_NO,
1141                                                              rh->offset,
1142                                                              &ticket_reissue_proc,
1143                                                              rh)))
1144   {
1145     GNUNET_break (0);
1146   }
1147   if (GNUNET_NO == ret)
1148   {
1149     send_revocation_finished (rh, GNUNET_OK);
1150     cleanup_revoke_ticket_handle (rh);
1151     return;
1152   }
1153 }
1154
1155 /**
1156  * Failed to check for attribute
1157  */
1158 static void
1159 check_attr_error (void *cls)
1160 {
1161   struct TicketRevocationHandle *rh = cls;
1162   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1163               "Unable to check for existing attribute\n");
1164   rh->ns_qe = NULL;
1165   send_revocation_finished (rh, GNUNET_SYSERR);
1166   cleanup_revoke_ticket_handle (rh);
1167 }
1168
1169
1170 /**
1171  * Revoke next attribte by reencryption with
1172  * new ABE master
1173  */
1174 static void
1175 reenc_next_attribute (void *cls);
1176
1177 /**
1178  * Check for existing attribute and overwrite
1179  */
1180 static void
1181 check_attr_cb (void *cls,
1182                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1183                const char *label,
1184                unsigned int rd_count,
1185                const struct GNUNET_GNSRECORD_Data *rd_old)
1186 {
1187   struct TicketRevocationHandle *rh = cls;
1188   struct TicketAttributeUpdateEntry *tue;
1189   struct GNUNET_GNSRECORD_Data rd[1];
1190   char* buf;
1191   size_t buf_size;
1192   char* new_label;
1193
1194   rh->ns_qe = NULL;
1195   if (1 != rd_count) {
1196     GNUNET_SCHEDULER_add_now (&reenc_next_attribute,
1197                               rh);
1198     return;
1199   }
1200
1201   buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (rh->attrs->list_head->claim);
1202   buf = GNUNET_malloc (buf_size);
1203   rh->attrs->list_head->claim->version++;
1204   GNUNET_RECLAIM_ATTRIBUTE_serialize (rh->attrs->list_head->claim,
1205                                       buf);
1206   tue = GNUNET_new (struct TicketAttributeUpdateEntry);
1207   tue->old_id = rh->attrs->list_head->claim->id;
1208   tue->new_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1209                                           UINT64_MAX);
1210   GNUNET_CONTAINER_DLL_insert (rh->attr_updates_head,
1211                                rh->attr_updates_tail,
1212                                tue);
1213   rh->attrs->list_head->claim->id = tue->new_id;
1214   new_label = GNUNET_STRINGS_data_to_string_alloc (&tue->new_id,
1215                                                    sizeof (uint64_t));
1216   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1217               "New attr id %s\n", new_label);
1218   rd[0].data_size = buf_size;
1219   rd[0].data = buf;
1220   rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
1221   rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1222   rd[0].expiration_time = rd_old[0].expiration_time;
1223   rh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1224                                               &rh->identity,
1225                                               new_label,
1226                                               1,
1227                                               rd,
1228                                               &attr_reenc_cont,
1229                                               rh);
1230 }
1231
1232
1233 /**
1234  * Revoke next attribte by reencryption with
1235  * new ABE master
1236  */
1237 static void
1238 reenc_next_attribute (void *cls)
1239 {
1240   struct TicketRevocationHandle *rh = cls;
1241   char *label;
1242   if (NULL == rh->attrs->list_head)
1243   {
1244     revocation_reissue_tickets (rh);
1245     return;
1246   }
1247   /* First check if attribute still exists */
1248   label = GNUNET_STRINGS_data_to_string_alloc (&rh->attrs->list_head->claim->id,
1249                                                sizeof (uint64_t));
1250   rh->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
1251                                                &rh->identity,
1252                                                label,
1253                                                &check_attr_error,
1254                                                rh,
1255                                                &check_attr_cb,
1256                                                rh);
1257   GNUNET_free (label);
1258 }
1259
1260
1261 /**
1262  * Namestore callback after revoked attribute
1263  * is stored
1264  */
1265 static void
1266 attr_reenc_cont (void *cls,
1267                  int32_t success,
1268                  const char *emsg)
1269 {
1270   struct TicketRevocationHandle *rh = cls;
1271   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1272
1273   rh->ns_qe = NULL;
1274   if (GNUNET_SYSERR == success)
1275   {
1276     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1277                 "Failed to reencrypt attribute %s\n",
1278                 emsg);
1279     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1280     return;
1281   }
1282   if (NULL == rh->attrs->list_head)
1283   {
1284     revocation_reissue_tickets (rh);
1285     return;
1286   }
1287   le = rh->attrs->list_head;
1288   GNUNET_CONTAINER_DLL_remove (rh->attrs->list_head,
1289                                rh->attrs->list_tail,
1290                                le);
1291   GNUNET_assert (NULL != rh->rvk_attrs);
1292   GNUNET_CONTAINER_DLL_insert (rh->rvk_attrs->list_head,
1293                                rh->rvk_attrs->list_tail,
1294                                le);
1295
1296
1297   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1298               "Re-encrypting next attribute\n");
1299   reenc_next_attribute (rh);
1300 }
1301
1302
1303 static void
1304 process_attributes_to_update (void *cls,
1305                               const struct GNUNET_RECLAIM_Ticket *ticket,
1306                               const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
1307 {
1308   struct TicketRevocationHandle *rh = cls;
1309
1310   rh->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
1311   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1312               "Revocation Phase I: Collecting attributes\n");
1313   /* Reencrypt all attributes with new key */
1314   if (NULL == rh->attrs->list_head)
1315   {
1316     /* No attributes to reencrypt */
1317     send_revocation_finished (rh, GNUNET_OK);
1318     cleanup_revoke_ticket_handle (rh);
1319     return;
1320   } else {
1321     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1322                 "Revocation Phase II: Re-encrypting attributes\n");
1323     reenc_next_attribute (rh);
1324   }
1325
1326 }
1327
1328
1329 static int
1330 check_revoke_ticket_message(void *cls,
1331                             const struct RevokeTicketMessage *im)
1332 {
1333   uint16_t size;
1334
1335   size = ntohs (im->header.size);
1336   if (size <= sizeof (struct RevokeTicketMessage))
1337   {
1338     GNUNET_break (0);
1339     return GNUNET_SYSERR;
1340   }
1341   return GNUNET_OK;
1342 }
1343
1344 static void
1345 handle_revoke_ticket_message (void *cls,
1346                               const struct RevokeTicketMessage *rm)
1347 {
1348   struct TicketRevocationHandle *rh;
1349   struct IdpClient *idp = cls;
1350   struct GNUNET_RECLAIM_Ticket *ticket;
1351
1352   rh = GNUNET_new (struct TicketRevocationHandle);
1353   ticket = (struct GNUNET_RECLAIM_Ticket*)&rm[1];
1354   rh->rvk_attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1355   rh->ticket = *ticket;
1356   rh->r_id = ntohl (rm->id);
1357   rh->client = idp;
1358   rh->identity = rm->identity;
1359   GNUNET_CRYPTO_ecdsa_key_get_public (&rh->identity,
1360                                       &rh->ticket.identity);
1361   GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head,
1362                                idp->revoke_op_tail,
1363                                rh);
1364   /**
1365    * TODO replace with GNS storage
1366    */
1367   TKT_database->get_ticket_attributes (TKT_database->cls,
1368                                        &rh->ticket,
1369                                        &process_attributes_to_update,
1370                                        rh);
1371   GNUNET_SERVICE_client_continue (idp->client);
1372
1373 }
1374
1375 /**
1376  * Cleanup ticket consume handle
1377  * @param handle the handle to clean up
1378  */
1379 static void
1380 cleanup_consume_ticket_handle (struct ConsumeTicketHandle *handle)
1381 {
1382   struct ParallelLookup *lu;
1383   struct ParallelLookup *tmp;
1384   if (NULL != handle->lookup_request)
1385     GNUNET_GNS_lookup_cancel (handle->lookup_request);
1386   for (lu = handle->parallel_lookups_head;
1387        NULL != lu;) {
1388     GNUNET_GNS_lookup_cancel (lu->lookup_request);
1389     GNUNET_free (lu->label);
1390     tmp = lu->next;
1391     GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
1392                                  handle->parallel_lookups_tail,
1393                                  lu);
1394     GNUNET_free (lu);
1395     lu = tmp;
1396   }
1397
1398   if (NULL != handle->attrs)
1399     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (handle->attrs);
1400   GNUNET_free (handle);
1401 }
1402
1403
1404
1405 static int
1406 check_consume_ticket_message(void *cls,
1407                              const struct ConsumeTicketMessage *cm)
1408 {
1409   uint16_t size;
1410
1411   size = ntohs (cm->header.size);
1412   if (size <= sizeof (struct ConsumeTicketMessage))
1413   {
1414     GNUNET_break (0);
1415     return GNUNET_SYSERR;
1416   }
1417   return GNUNET_OK;
1418 }
1419
1420 static void
1421 process_parallel_lookup2 (void *cls, uint32_t rd_count,
1422                           const struct GNUNET_GNSRECORD_Data *rd)
1423 {
1424   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1425               "Parallel lookup finished (count=%u)\n", rd_count);
1426   struct ParallelLookup *parallel_lookup = cls;
1427   struct ConsumeTicketHandle *handle = parallel_lookup->handle;
1428   struct ConsumeTicketResultMessage *crm;
1429   struct GNUNET_MQ_Envelope *env;
1430   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
1431   char *data_tmp;
1432   size_t attrs_len;
1433
1434   GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
1435                                handle->parallel_lookups_tail,
1436                                parallel_lookup);
1437   GNUNET_free (parallel_lookup->label);
1438
1439   GNUNET_STATISTICS_update (stats,
1440                             "attribute_lookup_time_total",
1441                             GNUNET_TIME_absolute_get_duration (parallel_lookup->lookup_start_time).rel_value_us,
1442                             GNUNET_YES);
1443   GNUNET_STATISTICS_update (stats,
1444                             "attribute_lookups_count",
1445                             1,
1446                             GNUNET_YES);
1447
1448
1449   GNUNET_free (parallel_lookup);
1450   if (1 != rd_count)
1451     GNUNET_break(0);//TODO
1452   if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR)
1453   {
1454     attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
1455     attr_le->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data,
1456                                                            rd->data_size);
1457     GNUNET_CONTAINER_DLL_insert (handle->attrs->list_head,
1458                                  handle->attrs->list_tail,
1459                                  attr_le);
1460   }
1461   if (NULL != handle->parallel_lookups_head)
1462     return; //Wait for more
1463   /* Else we are done */
1464
1465   /** Store ticket in DB
1466    * TODO: Store in GNS
1467    */
1468   if (GNUNET_OK != TKT_database->store_ticket (TKT_database->cls,
1469                                                &handle->ticket,
1470                                                handle->attrs))
1471   {
1472     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1473                 "Unable to store ticket after consume\n");
1474     GNUNET_break (0);
1475   }
1476
1477   GNUNET_SCHEDULER_cancel (handle->kill_task);
1478   attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (handle->attrs);
1479   env = GNUNET_MQ_msg_extra (crm,
1480                              attrs_len,
1481                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
1482   crm->id = htonl (handle->r_id);
1483   crm->attrs_len = htons (attrs_len);
1484   crm->identity = handle->ticket.identity;
1485   data_tmp = (char *) &crm[1];
1486   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (handle->attrs,
1487                                            data_tmp);
1488   GNUNET_MQ_send (handle->client->mq, env);
1489   GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head,
1490                                handle->client->consume_op_tail,
1491                                handle);
1492   cleanup_consume_ticket_handle (handle);
1493 }
1494
1495 void
1496 abort_parallel_lookups2 (void *cls)
1497 {
1498   struct ConsumeTicketHandle *handle = cls;
1499   struct ParallelLookup *lu;
1500   struct ParallelLookup *tmp;
1501   struct AttributeResultMessage *arm;
1502   struct GNUNET_MQ_Envelope *env;
1503
1504   handle->kill_task = NULL;
1505   for (lu = handle->parallel_lookups_head;
1506        NULL != lu;) {
1507     GNUNET_GNS_lookup_cancel (lu->lookup_request);
1508     GNUNET_free (lu->label);
1509     tmp = lu->next;
1510     GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
1511                                  handle->parallel_lookups_tail,
1512                                  lu);
1513     GNUNET_free (lu);
1514     lu = tmp;
1515   }
1516   env = GNUNET_MQ_msg (arm,
1517                        GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1518   arm->id = htonl (handle->r_id);
1519   arm->attr_len = htons (0);
1520   GNUNET_MQ_send (handle->client->mq, env);
1521
1522 }
1523
1524
1525 static void
1526 process_attr_labels (void *cls, uint32_t rd_count,
1527                      const struct GNUNET_GNSRECORD_Data *rd)
1528 {
1529   struct ConsumeTicketHandle *handle = cls;
1530   struct GNUNET_HashCode new_key_hash;
1531   struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
1532   struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
1533   struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key;
1534   struct ParallelLookup *parallel_lookup;
1535   size_t size;
1536   char *buf;
1537   char *attr_lbl;
1538   char *lbls;
1539
1540   handle->lookup_request = NULL;
1541   if (1 != rd_count)
1542   {
1543     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1544                 "Number of keys %d != 1.",
1545                 rd_count);
1546     cleanup_consume_ticket_handle (handle);
1547     GNUNET_CONTAINER_DLL_remove (handle->client->consume_op_head,
1548                                  handle->client->consume_op_tail,
1549                                  handle);
1550     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1551     return;
1552   }
1553
1554   //Decrypt
1555   ecdh_key = (struct GNUNET_CRYPTO_EcdhePublicKey *)rd->data;
1556
1557   buf = GNUNET_malloc (rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1558
1559   //Calculate symmetric key from ecdh parameters
1560   GNUNET_assert (GNUNET_OK ==
1561                  GNUNET_CRYPTO_ecdsa_ecdh (&handle->identity,
1562                                            ecdh_key,
1563                                            &new_key_hash));
1564   create_sym_key_from_ecdh (&new_key_hash,
1565                             &enc_key,
1566                             &enc_iv);
1567   size = GNUNET_CRYPTO_symmetric_decrypt (rd->data + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
1568                                           rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
1569                                           &enc_key,
1570                                           &enc_iv,
1571                                           buf);
1572
1573   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1574               "Decrypted bytes: %zd Expected bytes: %zd\n",
1575               size, rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1576   GNUNET_STATISTICS_update (stats,
1577                             "reclaim_authz_lookup_time_total",
1578                             GNUNET_TIME_absolute_get_duration (handle->lookup_start_time).rel_value_us,
1579                             GNUNET_YES);
1580   GNUNET_STATISTICS_update (stats,
1581                             "reclaim_authz_lookups_count",
1582                             1,
1583                             GNUNET_YES);
1584   lbls = GNUNET_strdup (buf);
1585   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1586               "Attributes found %s\n", lbls);
1587
1588   for (attr_lbl = strtok (lbls, ",");
1589        NULL != attr_lbl;
1590        attr_lbl = strtok (NULL, ","))
1591   {
1592     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1593                 "Looking up %s\n", attr_lbl);
1594     parallel_lookup = GNUNET_new (struct ParallelLookup);
1595     parallel_lookup->handle = handle;
1596     parallel_lookup->label = GNUNET_strdup (attr_lbl);
1597     parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get();
1598     parallel_lookup->lookup_request
1599       = GNUNET_GNS_lookup (gns_handle,
1600                            attr_lbl,
1601                            &handle->ticket.identity,
1602                            GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
1603                            GNUNET_GNS_LO_DEFAULT,
1604                            &process_parallel_lookup2,
1605                            parallel_lookup);
1606     GNUNET_CONTAINER_DLL_insert (handle->parallel_lookups_head,
1607                                  handle->parallel_lookups_tail,
1608                                  parallel_lookup);
1609   }
1610   GNUNET_free (lbls);
1611   GNUNET_free (buf);
1612   handle->kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES,3),
1613                                                     &abort_parallel_lookups2,
1614                                                     handle);
1615 }
1616
1617
1618 static void
1619 handle_consume_ticket_message (void *cls,
1620                                const struct ConsumeTicketMessage *cm)
1621 {
1622   struct ConsumeTicketHandle *ch;
1623   struct IdpClient *idp = cls;
1624   char* rnd_label;
1625
1626   ch = GNUNET_new (struct ConsumeTicketHandle);
1627   ch->r_id = ntohl (cm->id);
1628   ch->client = idp;
1629   ch->identity = cm->identity;
1630   ch->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1631   GNUNET_CRYPTO_ecdsa_key_get_public (&ch->identity,
1632                                       &ch->identity_pub);
1633   ch->ticket = *((struct GNUNET_RECLAIM_Ticket*)&cm[1]);
1634   rnd_label = GNUNET_STRINGS_data_to_string_alloc (&ch->ticket.rnd,
1635                                                    sizeof (uint64_t));
1636   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1637               "Looking for ABE key under %s\n", rnd_label);
1638   ch->lookup_start_time = GNUNET_TIME_absolute_get ();
1639   ch->lookup_request
1640     = GNUNET_GNS_lookup (gns_handle,
1641                          rnd_label,
1642                          &ch->ticket.identity,
1643                          GNUNET_GNSRECORD_TYPE_RECLAIM_AUTHZ,
1644                          GNUNET_GNS_LO_DEFAULT,
1645                          &process_attr_labels,
1646                          ch);
1647   GNUNET_CONTAINER_DLL_insert (idp->consume_op_head,
1648                                idp->consume_op_tail,
1649                                ch);
1650   GNUNET_free (rnd_label);
1651   GNUNET_SERVICE_client_continue (idp->client);
1652 }
1653
1654 /**
1655  * Cleanup attribute store handle
1656  *
1657  * @param handle handle to clean up
1658  */
1659 static void
1660 cleanup_as_handle (struct AttributeStoreHandle *ash)
1661 {
1662   if (NULL != ash->ns_qe)
1663     GNUNET_NAMESTORE_cancel (ash->ns_qe);
1664   if (NULL != ash->claim)
1665     GNUNET_free (ash->claim);
1666   GNUNET_free (ash);
1667 }
1668
1669 static void
1670 attr_store_cont (void *cls,
1671                  int32_t success,
1672                  const char *emsg)
1673 {
1674   struct AttributeStoreHandle *ash = cls;
1675   struct GNUNET_MQ_Envelope *env;
1676   struct AttributeStoreResultMessage *acr_msg;
1677
1678   ash->ns_qe = NULL;
1679   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
1680                                ash->client->store_op_tail,
1681                                ash);
1682
1683   if (GNUNET_SYSERR == success)
1684   {
1685     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1686                 "Failed to store attribute %s\n",
1687                 emsg);
1688     cleanup_as_handle (ash);
1689     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1690     return;
1691   }
1692
1693   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1694               "Sending ATTRIBUTE_STORE_RESPONSE message\n");
1695   env = GNUNET_MQ_msg (acr_msg,
1696                        GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE);
1697   acr_msg->id = htonl (ash->r_id);
1698   acr_msg->op_result = htonl (GNUNET_OK);
1699   GNUNET_MQ_send (ash->client->mq,
1700                   env);
1701   cleanup_as_handle (ash);
1702 }
1703
1704 /**
1705  * Adds a new attribute
1706  *
1707  * @param cls the AttributeStoreHandle
1708  */
1709 static void
1710 attr_store_task (void *cls)
1711 {
1712   struct AttributeStoreHandle *ash = cls;
1713   struct GNUNET_GNSRECORD_Data rd[1];
1714   char* buf;
1715   char* label;
1716   size_t buf_size;
1717
1718   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1719               "Storing attribute\n");
1720   buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (ash->claim);
1721   buf = GNUNET_malloc (buf_size);
1722   //Give the ash a new id
1723   ash->claim->id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1724                                              UINT64_MAX);
1725   GNUNET_RECLAIM_ATTRIBUTE_serialize (ash->claim,
1726                                       buf);
1727   label = GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id,
1728                                                sizeof (uint64_t));
1729   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1730               "Encrypting with label %s\n", label);
1731
1732   rd[0].data_size = buf_size;
1733   rd[0].data = buf;
1734   rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
1735   rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1736   rd[0].expiration_time = ash->exp.rel_value_us;
1737   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1738                                                &ash->identity,
1739                                                label,
1740                                                1,
1741                                                rd,
1742                                                &attr_store_cont,
1743                                                ash);
1744   GNUNET_free (buf);
1745 }
1746
1747
1748 static int
1749 check_attribute_store_message(void *cls,
1750                               const struct AttributeStoreMessage *sam)
1751 {
1752   uint16_t size;
1753
1754   size = ntohs (sam->header.size);
1755   if (size <= sizeof (struct AttributeStoreMessage))
1756   {
1757     GNUNET_break (0);
1758     return GNUNET_SYSERR;
1759   }
1760   return GNUNET_OK;
1761 }
1762
1763
1764 static void
1765 handle_attribute_store_message (void *cls,
1766                                 const struct AttributeStoreMessage *sam)
1767 {
1768   struct AttributeStoreHandle *ash;
1769   struct IdpClient *idp = cls;
1770   size_t data_len;
1771   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1772               "Received ATTRIBUTE_STORE message\n");
1773
1774   data_len = ntohs (sam->attr_len);
1775
1776   ash = GNUNET_new (struct AttributeStoreHandle);
1777   ash->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char*)&sam[1],
1778                                                            data_len);
1779
1780   ash->r_id = ntohl (sam->id);
1781   ash->identity = sam->identity;
1782   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1783   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity,
1784                                       &ash->identity_pkey);
1785
1786   GNUNET_SERVICE_client_continue (idp->client);
1787   ash->client = idp;
1788   GNUNET_CONTAINER_DLL_insert (idp->store_op_head,
1789                                idp->store_op_tail,
1790                                ash);
1791   GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
1792 }
1793
1794 static void
1795 cleanup_attribute_iter_handle (struct AttributeIterator *ai)
1796 {
1797   GNUNET_free (ai);
1798 }
1799
1800 static void
1801 attr_iter_error (void *cls)
1802 {
1803   struct AttributeIterator *ai = cls;
1804   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1805               "Failed to iterate over attributes\n");
1806   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1807                                ai->client->attr_iter_tail,
1808                                ai);
1809   cleanup_attribute_iter_handle (ai);
1810   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1811 }
1812
1813 static void
1814 attr_iter_finished (void *cls)
1815 {
1816   struct AttributeIterator *ai = cls;
1817   struct GNUNET_MQ_Envelope *env;
1818   struct AttributeResultMessage *arm;
1819
1820   env = GNUNET_MQ_msg (arm,
1821                        GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1822   arm->id = htonl (ai->request_id);
1823   arm->attr_len = htons (0);
1824   GNUNET_MQ_send (ai->client->mq, env);
1825   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1826                                ai->client->attr_iter_tail,
1827                                ai);
1828   cleanup_attribute_iter_handle (ai);
1829 }
1830
1831 static void
1832 attr_iter_cb (void *cls,
1833               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1834               const char *label,
1835               unsigned int rd_count,
1836               const struct GNUNET_GNSRECORD_Data *rd)
1837 {
1838   struct AttributeIterator *ai = cls;
1839   struct AttributeResultMessage *arm;
1840   struct GNUNET_MQ_Envelope *env;
1841   char* data_tmp;
1842
1843   if (rd_count != 1)
1844   {
1845     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
1846                                          1);
1847     return;
1848   }
1849
1850   if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd->record_type)
1851   {
1852     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
1853                                          1);
1854     return;
1855   }
1856   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1857               "Found attribute under: %s\n", label);
1858   env = GNUNET_MQ_msg_extra (arm,
1859                              rd->data_size,
1860                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1861   arm->id = htonl (ai->request_id);
1862   arm->attr_len = htons (rd->data_size);
1863   GNUNET_CRYPTO_ecdsa_key_get_public (zone,
1864                                       &arm->identity);
1865   data_tmp = (char *) &arm[1];
1866   GNUNET_memcpy (data_tmp,
1867                  rd->data,
1868                  rd->data_size);
1869   GNUNET_MQ_send (ai->client->mq, env);
1870 }
1871
1872
1873 static void
1874 handle_iteration_start (void *cls,
1875                         const struct AttributeIterationStartMessage *ais_msg)
1876 {
1877   struct IdpClient *idp = cls;
1878   struct AttributeIterator *ai;
1879
1880   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1881               "Received ATTRIBUTE_ITERATION_START message\n");
1882   ai = GNUNET_new (struct AttributeIterator);
1883   ai->request_id = ntohl (ais_msg->id);
1884   ai->client = idp;
1885   ai->identity = ais_msg->identity;
1886
1887   GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head,
1888                                idp->attr_iter_tail,
1889                                ai);
1890   ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1891                                                      &ai->identity,
1892                                                      &attr_iter_error,
1893                                                      ai,
1894                                                      &attr_iter_cb,
1895                                                      ai,
1896                                                      &attr_iter_finished,
1897                                                      ai);
1898   GNUNET_SERVICE_client_continue (idp->client);
1899 }
1900
1901
1902 static void
1903 handle_iteration_stop (void *cls,
1904                        const struct AttributeIterationStopMessage *ais_msg)
1905 {
1906   struct IdpClient *idp = cls;
1907   struct AttributeIterator *ai;
1908   uint32_t rid;
1909
1910   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1911               "Received `%s' message\n",
1912               "ATTRIBUTE_ITERATION_STOP");
1913   rid = ntohl (ais_msg->id);
1914   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1915     if (ai->request_id == rid)
1916       break;
1917   if (NULL == ai)
1918   {
1919     GNUNET_break (0);
1920     GNUNET_SERVICE_client_drop (idp->client);
1921     return;
1922   }
1923   GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head,
1924                                idp->attr_iter_tail,
1925                                ai);
1926   GNUNET_free (ai);
1927   GNUNET_SERVICE_client_continue (idp->client);
1928 }
1929
1930
1931 static void
1932 handle_iteration_next (void *cls,
1933                        const struct AttributeIterationNextMessage *ais_msg)
1934 {
1935   struct IdpClient *idp = cls;
1936   struct AttributeIterator *ai;
1937   uint32_t rid;
1938
1939   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1940               "Received ATTRIBUTE_ITERATION_NEXT message\n");
1941   rid = ntohl (ais_msg->id);
1942   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1943     if (ai->request_id == rid)
1944       break;
1945   if (NULL == ai)
1946   {
1947     GNUNET_break (0);
1948     GNUNET_SERVICE_client_drop (idp->client);
1949     return;
1950   }
1951   GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it,
1952                                        1);
1953   GNUNET_SERVICE_client_continue (idp->client);
1954 }
1955
1956 /**
1957  * Ticket iteration processor result
1958  */
1959 enum ZoneIterationResult
1960 {
1961   /**
1962    * Iteration start.
1963    */
1964   IT_START = 0,
1965
1966   /**
1967    * Found tickets,
1968    * Continue to iterate with next iteration_next call
1969    */
1970   IT_SUCCESS_MORE_AVAILABLE = 1,
1971
1972   /**
1973    * Iteration complete
1974    */
1975   IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE = 2
1976 };
1977
1978
1979 /**
1980  * Context for ticket iteration
1981  */
1982 struct TicketIterationProcResult
1983 {
1984   /**
1985    * The ticket iteration handle
1986    */
1987   struct TicketIteration *ti;
1988
1989   /**
1990    * Iteration result: iteration done?
1991    * #IT_SUCCESS_MORE_AVAILABLE:  if there may be more results overall but
1992    * we got one for now and have sent it to the client
1993    * #IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE: if there are no further results,
1994    * #IT_START: if we are still trying to find a result.
1995    */
1996   int res_iteration_finished;
1997
1998 };
1999
2000 static void
2001 cleanup_ticket_iter_handle (struct TicketIteration *ti)
2002 {
2003   GNUNET_free (ti);
2004 }
2005
2006 /**
2007  * Process ticket from database
2008  *
2009  * @param cls struct TicketIterationProcResult
2010  * @param ticket the ticket
2011  * @param attrs the attributes
2012  */
2013 static void
2014 ticket_iterate_proc (void *cls,
2015                      const struct GNUNET_RECLAIM_Ticket *ticket,
2016                      const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
2017 {
2018   struct TicketIterationProcResult *proc = cls;
2019
2020   if (NULL == ticket)
2021   {
2022     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2023                 "Iteration done\n");
2024     proc->res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
2025     return;
2026   }
2027   proc->res_iteration_finished = IT_SUCCESS_MORE_AVAILABLE;
2028   send_ticket_result (proc->ti->client,
2029                       proc->ti->r_id,
2030                       ticket,
2031                       attrs);
2032
2033 }
2034
2035 /**
2036  * Perform ticket iteration step
2037  *
2038  * @param ti ticket iterator to process
2039  */
2040 static void
2041 run_ticket_iteration_round (struct TicketIteration *ti)
2042 {
2043   struct TicketIterationProcResult proc;
2044   struct GNUNET_MQ_Envelope *env;
2045   struct TicketResultMessage *trm;
2046   int ret;
2047
2048   memset (&proc, 0, sizeof (proc));
2049   proc.ti = ti;
2050   proc.res_iteration_finished = IT_START;
2051   while (IT_START == proc.res_iteration_finished)
2052   {
2053     if (GNUNET_SYSERR ==
2054         (ret = TKT_database->iterate_tickets (TKT_database->cls,
2055                                               &ti->identity,
2056                                               ti->is_audience,
2057                                               ti->offset,
2058                                               &ticket_iterate_proc,
2059                                               &proc)))
2060     {
2061       GNUNET_break (0);
2062       break;
2063     }
2064     if (GNUNET_NO == ret)
2065       proc.res_iteration_finished = IT_SUCCESS_NOT_MORE_RESULTS_AVAILABLE;
2066     ti->offset++;
2067   }
2068   if (IT_SUCCESS_MORE_AVAILABLE == proc.res_iteration_finished)
2069   {
2070     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2071                 "More results available\n");
2072     return; /* more later */
2073   }
2074   /* send empty response to indicate end of list */
2075   env = GNUNET_MQ_msg (trm,
2076                        GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
2077   trm->id = htonl (ti->r_id);
2078   GNUNET_MQ_send (ti->client->mq,
2079                   env);
2080   GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
2081                                ti->client->ticket_iter_tail,
2082                                ti);
2083   cleanup_ticket_iter_handle (ti);
2084 }
2085
2086 static void
2087 handle_ticket_iteration_start (void *cls,
2088                                const struct TicketIterationStartMessage *tis_msg)
2089 {
2090   struct IdpClient *client = cls;
2091   struct TicketIteration *ti;
2092
2093   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2094               "Received TICKET_ITERATION_START message\n");
2095   ti = GNUNET_new (struct TicketIteration);
2096   ti->r_id = ntohl (tis_msg->id);
2097   ti->offset = 0;
2098   ti->client = client;
2099   ti->identity = tis_msg->identity;
2100   ti->is_audience = ntohl (tis_msg->is_audience);
2101
2102   GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
2103                                client->ticket_iter_tail,
2104                                ti);
2105   run_ticket_iteration_round (ti);
2106   GNUNET_SERVICE_client_continue (client->client);
2107 }
2108
2109
2110 static void
2111 handle_ticket_iteration_stop (void *cls,
2112                               const struct TicketIterationStopMessage *tis_msg)
2113 {
2114   struct IdpClient *client = cls;
2115   struct TicketIteration *ti;
2116   uint32_t rid;
2117
2118   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2119               "Received `%s' message\n",
2120               "TICKET_ITERATION_STOP");
2121   rid = ntohl (tis_msg->id);
2122   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2123     if (ti->r_id == rid)
2124       break;
2125   if (NULL == ti)
2126   {
2127     GNUNET_break (0);
2128     GNUNET_SERVICE_client_drop (client->client);
2129     return;
2130   }
2131   GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
2132                                client->ticket_iter_tail,
2133                                ti);
2134   cleanup_ticket_iter_handle (ti);
2135   GNUNET_SERVICE_client_continue (client->client);
2136 }
2137
2138
2139 static void
2140 handle_ticket_iteration_next (void *cls,
2141                               const struct TicketIterationNextMessage *tis_msg)
2142 {
2143   struct IdpClient *client = cls;
2144   struct TicketIteration *ti;
2145   uint32_t rid;
2146
2147   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2148               "Received TICKET_ITERATION_NEXT message\n");
2149   rid = ntohl (tis_msg->id);
2150   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
2151     if (ti->r_id == rid)
2152       break;
2153   if (NULL == ti)
2154   {
2155     GNUNET_break (0);
2156     GNUNET_SERVICE_client_drop (client->client);
2157     return;
2158   }
2159   run_ticket_iteration_round (ti);
2160   GNUNET_SERVICE_client_continue (client->client);
2161 }
2162
2163
2164
2165
2166 /**
2167  * Main function that will be run
2168  *
2169  * @param cls closure
2170  * @param c the configuration used
2171  * @param server the service handle
2172  */
2173 static void
2174 run (void *cls,
2175      const struct GNUNET_CONFIGURATION_Handle *c,
2176      struct GNUNET_SERVICE_Handle *server)
2177 {
2178   char *database;
2179   cfg = c;
2180
2181   stats = GNUNET_STATISTICS_create ("reclaim", cfg);
2182
2183   //Connect to identity and namestore services
2184   nsh = GNUNET_NAMESTORE_connect (cfg);
2185   if (NULL == nsh)
2186   {
2187     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
2188   }
2189
2190   gns_handle = GNUNET_GNS_connect (cfg);
2191   if (NULL == gns_handle)
2192   {
2193     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
2194   }
2195   credential_handle = GNUNET_CREDENTIAL_connect (cfg);
2196   if (NULL == credential_handle)
2197   {
2198     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential");
2199   }
2200   identity_handle = GNUNET_IDENTITY_connect (cfg,
2201                                              NULL,
2202                                              NULL);
2203   /* Loading DB plugin */
2204   if (GNUNET_OK !=
2205       GNUNET_CONFIGURATION_get_value_string (cfg,
2206                                              "reclaim",
2207                                              "database",
2208                                              &database))
2209     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2210                 "No database backend configured\n");
2211   GNUNET_asprintf (&db_lib_name,
2212                    "libgnunet_plugin_reclaim_%s",
2213                    database);
2214   TKT_database = GNUNET_PLUGIN_load (db_lib_name,
2215                                      (void *) cfg);
2216   GNUNET_free (database);
2217   if (NULL == TKT_database)
2218   {
2219     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2220                 "Could not load database backend `%s'\n",
2221                 db_lib_name);
2222     GNUNET_SCHEDULER_shutdown ();
2223     return;
2224   }
2225
2226   if (GNUNET_OK ==
2227       GNUNET_CONFIGURATION_get_value_time (cfg,
2228                                            "reclaim",
2229                                            "TOKEN_EXPIRATION_INTERVAL",
2230                                            &token_expiration_interval))
2231   {
2232     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2233                 "Time window for zone iteration: %s\n",
2234                 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
2235                                                         GNUNET_YES));
2236   } else {
2237     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
2238   }
2239
2240   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
2241 }
2242
2243 /**
2244  * Called whenever a client is disconnected.
2245  *
2246  * @param cls closure
2247  * @param client identification of the client
2248  * @param app_ctx @a client
2249  */
2250 static void
2251 client_disconnect_cb (void *cls,
2252                       struct GNUNET_SERVICE_Client *client,
2253                       void *app_ctx)
2254 {
2255   struct IdpClient *idp = app_ctx;
2256   struct AttributeIterator *ai;
2257   struct TicketIteration *ti;
2258   struct TicketRevocationHandle *rh;
2259   struct TicketIssueHandle *iss;
2260   struct ConsumeTicketHandle *ct;
2261   struct AttributeStoreHandle *as;
2262
2263   //TODO other operations
2264
2265   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2266               "Client %p disconnected\n",
2267               client);
2268
2269   while (NULL != (iss = idp->issue_op_head))
2270   {
2271     GNUNET_CONTAINER_DLL_remove (idp->issue_op_head,
2272                                  idp->issue_op_tail,
2273                                  iss);
2274     cleanup_ticket_issue_handle (iss);
2275   }
2276   while (NULL != (ct = idp->consume_op_head))
2277   {
2278     GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
2279                                  idp->consume_op_tail,
2280                                  ct);
2281     cleanup_consume_ticket_handle (ct);
2282   }
2283   while (NULL != (as = idp->store_op_head))
2284   {
2285     GNUNET_CONTAINER_DLL_remove (idp->store_op_head,
2286                                  idp->store_op_tail,
2287                                  as);
2288     cleanup_as_handle (as);
2289   }
2290
2291   while (NULL != (ai = idp->attr_iter_head))
2292   {
2293     GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head,
2294                                  idp->attr_iter_tail,
2295                                  ai);
2296     cleanup_attribute_iter_handle (ai);
2297   }
2298   while (NULL != (rh = idp->revoke_op_head))
2299   {
2300     GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head,
2301                                  idp->revoke_op_tail,
2302                                  rh);
2303     cleanup_revoke_ticket_handle (rh);
2304   }
2305   while (NULL != (ti = idp->ticket_iter_head))
2306   {
2307     GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
2308                                  idp->ticket_iter_tail,
2309                                  ti);
2310     cleanup_ticket_iter_handle (ti);
2311   }
2312   GNUNET_free (idp);
2313 }
2314
2315
2316 /**
2317  * Add a client to our list of active clients.
2318  *
2319  * @param cls NULL
2320  * @param client client to add
2321  * @param mq message queue for @a client
2322  * @return internal namestore client structure for this client
2323  */
2324 static void *
2325 client_connect_cb (void *cls,
2326                    struct GNUNET_SERVICE_Client *client,
2327                    struct GNUNET_MQ_Handle *mq)
2328 {
2329   struct IdpClient *idp;
2330   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2331               "Client %p connected\n",
2332               client);
2333   idp = GNUNET_new (struct IdpClient);
2334   idp->client = client;
2335   idp->mq = mq;
2336   return idp;
2337 }
2338
2339
2340
2341 /**
2342  * Define "main" method using service macro.
2343  */
2344 GNUNET_SERVICE_MAIN
2345 ("reclaim",
2346  GNUNET_SERVICE_OPTION_NONE,
2347  &run,
2348  &client_connect_cb,
2349  &client_disconnect_cb,
2350  NULL,
2351  GNUNET_MQ_hd_var_size (attribute_store_message,
2352                         GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
2353                         struct AttributeStoreMessage,
2354                         NULL),
2355  GNUNET_MQ_hd_fixed_size (iteration_start,
2356                           GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
2357                           struct AttributeIterationStartMessage,
2358                           NULL),
2359  GNUNET_MQ_hd_fixed_size (iteration_next,
2360                           GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
2361                           struct AttributeIterationNextMessage,
2362                           NULL),
2363  GNUNET_MQ_hd_fixed_size (iteration_stop,
2364                           GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
2365                           struct AttributeIterationStopMessage,
2366                           NULL),
2367  GNUNET_MQ_hd_var_size (issue_ticket_message,
2368                         GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
2369                         struct IssueTicketMessage,
2370                         NULL),
2371  GNUNET_MQ_hd_var_size (consume_ticket_message,
2372                         GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
2373                         struct ConsumeTicketMessage,
2374                         NULL),
2375  GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
2376                           GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
2377                           struct TicketIterationStartMessage,
2378                           NULL),
2379  GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
2380                           GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
2381                           struct TicketIterationNextMessage,
2382                           NULL),
2383  GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
2384                           GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
2385                           struct TicketIterationStopMessage,
2386                           NULL),
2387  GNUNET_MQ_hd_var_size (revoke_ticket_message,
2388                         GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
2389                         struct RevokeTicketMessage,
2390                         NULL),
2391  GNUNET_MQ_handler_end());
2392 /* end of gnunet-service-reclaim.c */