RECLAIM: less unneccessary crypto; syntax and build fixes
[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
28 #include "gnunet_util_lib.h"
29
30 #include "gnunet-service-reclaim_tickets.h"
31 #include "gnunet_constants.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_identity_service.h"
34 #include "gnunet_namestore_service.h"
35 #include "gnunet_protocols.h"
36 #include "gnunet_reclaim_attribute_lib.h"
37 #include "gnunet_reclaim_plugin.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  * Timeout task
88  */
89 static struct GNUNET_SCHEDULER_Task *timeout_task;
90
91 /**
92  * Update task
93  */
94 static struct GNUNET_SCHEDULER_Task *update_task;
95
96 /**
97  * Our configuration.
98  */
99 static const struct GNUNET_CONFIGURATION_Handle *cfg;
100
101 /**
102  * An idp client
103  */
104 struct IdpClient;
105
106 /**
107  * A ticket iteration operation.
108  */
109 struct TicketIteration {
110   /**
111    * DLL
112    */
113   struct TicketIteration *next;
114
115   /**
116    * DLL
117    */
118   struct TicketIteration *prev;
119
120   /**
121    * Client which intiated this zone iteration
122    */
123   struct IdpClient *client;
124
125   /**
126    * The operation id fot the iteration in the response for the client
127    */
128   uint32_t r_id;
129
130   /**
131    * The ticket iterator
132    */
133   struct RECLAIM_TICKETS_Iterator *iter;
134 };
135
136 /**
137  * An attribute iteration operation.
138  */
139 struct AttributeIterator {
140   /**
141    * Next element in the DLL
142    */
143   struct AttributeIterator *next;
144
145   /**
146    * Previous element in the DLL
147    */
148   struct AttributeIterator *prev;
149
150   /**
151    * IDP client which intiated this zone iteration
152    */
153   struct IdpClient *client;
154
155   /**
156    * Key of the zone we are iterating over.
157    */
158   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
159
160   /**
161    * Namestore iterator
162    */
163   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
164
165   /**
166    * The operation id fot the zone iteration in the response for the client
167    */
168   uint32_t request_id;
169 };
170
171 /**
172  * An idp client
173  */
174 struct IdpClient {
175
176   /**
177    * The client
178    */
179   struct GNUNET_SERVICE_Client *client;
180
181   /**
182    * Message queue for transmission to @e client
183    */
184   struct GNUNET_MQ_Handle *mq;
185
186   /**
187    * Head of the DLL of
188    * Attribute iteration operations in
189    * progress initiated by this client
190    */
191   struct AttributeIterator *attr_iter_head;
192
193   /**
194    * Tail of the DLL of
195    * Attribute iteration operations
196    * in progress initiated by this client
197    */
198   struct AttributeIterator *attr_iter_tail;
199
200   /**
201    * Head of DLL of ticket iteration ops
202    */
203   struct TicketIteration *ticket_iter_head;
204
205   /**
206    * Tail of DLL of ticket iteration ops
207    */
208   struct TicketIteration *ticket_iter_tail;
209
210   /**
211    * Head of DLL of ticket revocation ops
212    */
213   struct TicketRevocationHandle *revoke_op_head;
214
215   /**
216    * Tail of DLL of ticket revocation ops
217    */
218   struct TicketRevocationHandle *revoke_op_tail;
219
220   /**
221    * Head of DLL of ticket issue ops
222    */
223   struct TicketIssueOperation *issue_op_head;
224
225   /**
226    * Tail of DLL of ticket issue ops
227    */
228   struct TicketIssueOperation *issue_op_tail;
229
230   /**
231    * Head of DLL of ticket consume ops
232    */
233   struct ConsumeTicketOperation *consume_op_head;
234
235   /**
236    * Tail of DLL of ticket consume ops
237    */
238   struct ConsumeTicketOperation *consume_op_tail;
239
240   /**
241    * Head of DLL of attribute store ops
242    */
243   struct AttributeStoreHandle *store_op_head;
244
245   /**
246    * Tail of DLL of attribute store ops
247    */
248   struct AttributeStoreHandle *store_op_tail;
249 };
250
251 struct AttributeStoreHandle {
252   /**
253    * DLL
254    */
255   struct AttributeStoreHandle *next;
256
257   /**
258    * DLL
259    */
260   struct AttributeStoreHandle *prev;
261
262   /**
263    * Client connection
264    */
265   struct IdpClient *client;
266
267   /**
268    * Identity
269    */
270   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
271
272   /**
273    * Identity pubkey
274    */
275   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
276
277   /**
278    * QueueEntry
279    */
280   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
281
282   /**
283    * The attribute to store
284    */
285   struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
286
287   /**
288    * The attribute expiration interval
289    */
290   struct GNUNET_TIME_Relative exp;
291
292   /**
293    * request id
294    */
295   uint32_t r_id;
296 };
297
298 struct ConsumeTicketOperation {
299   /**
300    * DLL
301    */
302   struct ConsumeTicketOperation *next;
303
304   /**
305    * DLL
306    */
307   struct ConsumeTicketOperation *prev;
308
309   /**
310    * Client connection
311    */
312   struct IdpClient *client;
313
314   /**
315    * request id
316    */
317   uint32_t r_id;
318
319   /**
320    * Ticket consume handle
321    */
322   struct RECLAIM_TICKETS_ConsumeHandle *ch;
323 };
324
325 /**
326  * Updated attribute IDs
327  */
328 struct TicketAttributeUpdateEntry {
329   /**
330    * DLL
331    */
332   struct TicketAttributeUpdateEntry *next;
333
334   /**
335    * DLL
336    */
337   struct TicketAttributeUpdateEntry *prev;
338
339   /**
340    * The old ID
341    */
342   uint64_t old_id;
343
344   /**
345    * The new ID
346    */
347   uint64_t new_id;
348 };
349
350 /**
351  * Ticket revocation request handle
352  */
353 struct TicketRevocationHandle {
354   /**
355    * DLL
356    */
357   struct TicketRevocationHandle *prev;
358
359   /**
360    * DLL
361    */
362   struct TicketRevocationHandle *next;
363
364   /**
365    * Attribute updates
366    */
367   struct TicketAttributeUpdateEntry *attr_updates_head;
368
369   /**
370    * Attribute updates
371    */
372   struct TicketAttributeUpdateEntry *attr_updates_tail;
373
374   /**
375    * Client connection
376    */
377   struct IdpClient *client;
378
379   /**
380    * Attributes to reissue
381    */
382   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
383
384   /**
385    * Attributes to revoke
386    */
387   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *rvk_attrs;
388
389   /**
390    * Issuer Key
391    */
392   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
393
394   /**
395    * Ticket to issue
396    */
397   struct GNUNET_RECLAIM_Ticket ticket;
398
399   /**
400    * QueueEntry
401    */
402   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
403
404   /**
405    * Namestore iterator
406    */
407   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
408
409   /**
410    * Offset
411    */
412   uint32_t offset;
413
414   /**
415    * request id
416    */
417   uint32_t r_id;
418 };
419
420 /**
421  * Ticket issue operation handle
422  */
423 struct TicketIssueOperation {
424   /**
425    * DLL
426    */
427   struct TicketIssueOperation *prev;
428
429   /**
430    * DLL
431    */
432   struct TicketIssueOperation *next;
433
434   /**
435    * Client connection
436    */
437   struct IdpClient *client;
438
439   /**
440    * request id
441    */
442   uint32_t r_id;
443 };
444
445 /**
446  * DLL for ego handles to egos containing the RECLAIM_ATTRS in a
447  * map in json_t format
448  *
449  */
450 struct EgoEntry {
451   /**
452    * DLL
453    */
454   struct EgoEntry *next;
455
456   /**
457    * DLL
458    */
459   struct EgoEntry *prev;
460
461   /**
462    * Ego handle
463    */
464   struct GNUNET_IDENTITY_Ego *ego;
465
466   /**
467    * Attribute map. Contains the attributes as json_t
468    */
469   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
470 };
471
472 /**
473  * Cleanup task
474  */
475 static void cleanup ()
476 {
477   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
478
479   RECLAIM_TICKETS_deinit ();
480   GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, TKT_database));
481   GNUNET_free (db_lib_name);
482   db_lib_name = NULL;
483   if (NULL != timeout_task)
484     GNUNET_SCHEDULER_cancel (timeout_task);
485   if (NULL != update_task)
486     GNUNET_SCHEDULER_cancel (update_task);
487   if (NULL != identity_handle)
488     GNUNET_IDENTITY_disconnect (identity_handle);
489   if (NULL != nsh)
490     GNUNET_NAMESTORE_disconnect (nsh);
491 }
492
493 /**
494  * Shutdown task
495  *
496  * @param cls NULL
497  */
498 static void do_shutdown (void *cls)
499 {
500   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
501   cleanup ();
502 }
503
504 static int create_sym_key_from_ecdh (
505     const struct GNUNET_HashCode *new_key_hash,
506     struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
507     struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
508 {
509   struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
510
511   GNUNET_CRYPTO_hash_to_enc (new_key_hash, &new_key_hash_str);
512   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n",
513               (char *)&new_key_hash_str);
514   static const char ctx_key[] = "gnuid-aes-ctx-key";
515   GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
516                      new_key_hash, sizeof (struct GNUNET_HashCode), ctx_key,
517                      strlen (ctx_key), NULL, 0);
518   static const char ctx_iv[] = "gnuid-aes-ctx-iv";
519   GNUNET_CRYPTO_kdf (
520       iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
521       new_key_hash, sizeof (struct GNUNET_HashCode), ctx_iv, strlen (ctx_iv),
522       NULL, 0);
523   return GNUNET_OK;
524 }
525
526 static void send_ticket_result (const struct IdpClient *client, uint32_t r_id,
527                                 const struct GNUNET_RECLAIM_Ticket *ticket,
528                                 uint32_t success)
529 {
530   struct TicketResultMessage *irm;
531   struct GNUNET_MQ_Envelope *env;
532   struct GNUNET_RECLAIM_Ticket *ticket_buf;
533
534   if (NULL != ticket) {
535     env = GNUNET_MQ_msg_extra (irm, sizeof (struct GNUNET_RECLAIM_Ticket),
536                                GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
537     ticket_buf = (struct GNUNET_RECLAIM_Ticket *)&irm[1];
538     *ticket_buf = *ticket;
539   } else {
540     env = GNUNET_MQ_msg (irm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
541   }
542   // TODO add success member
543   irm->id = htonl (r_id);
544   GNUNET_MQ_send (client->mq, env);
545 }
546
547 static void issue_ticket_result_cb (void *cls,
548                                     struct GNUNET_RECLAIM_Ticket *ticket,
549                                     uint32_t success, const char *emsg)
550 {
551   struct TicketIssueOperation *tio = cls;
552   if (GNUNET_OK != success) {
553     send_ticket_result (tio->client, tio->r_id, NULL, GNUNET_SYSERR);
554     GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
555                                  tio->client->issue_op_tail, tio);
556     GNUNET_free (tio);
557     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error issuing ticket: %s\n", emsg);
558     return;
559   }
560   send_ticket_result (tio->client, tio->r_id, ticket, GNUNET_SYSERR);
561   GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
562                                tio->client->issue_op_tail, tio);
563   GNUNET_free (tio);
564 }
565
566 static int check_issue_ticket_message (void *cls,
567                                        const struct IssueTicketMessage *im)
568 {
569   uint16_t size;
570
571   size = ntohs (im->header.size);
572   if (size <= sizeof (struct IssueTicketMessage)) {
573     GNUNET_break (0);
574     return GNUNET_SYSERR;
575   }
576   return GNUNET_OK;
577 }
578
579 static void handle_issue_ticket_message (void *cls,
580                                          const struct IssueTicketMessage *im)
581 {
582   struct TicketIssueOperation *tio;
583   struct IdpClient *idp = cls;
584   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
585   size_t attrs_len;
586
587   tio = GNUNET_new (struct TicketIssueOperation);
588   attrs_len = ntohs (im->attr_len);
589   attrs = GNUNET_RECLAIM_ATTRIBUTE_list_deserialize ((char *)&im[1], attrs_len);
590   tio->r_id = ntohl (im->id);
591   tio->client = idp;
592   GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, idp->issue_op_tail, tio);
593   RECLAIM_TICKETS_issue (&im->identity, attrs, &im->rp, &issue_ticket_result_cb,
594                          tio);
595   GNUNET_SERVICE_client_continue (idp->client);
596   GNUNET_RECLAIM_ATTRIBUTE_list_destroy (attrs);
597 }
598
599 /**********************************************************
600  * Revocation
601  **********************************************************/
602
603 /**
604  * Cleanup revoke handle
605  *
606  * @param rh the ticket revocation handle
607  */
608 static void cleanup_revoke_ticket_handle (struct TicketRevocationHandle *rh)
609 {
610   if (NULL != rh->attrs)
611     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->attrs);
612   if (NULL != rh->rvk_attrs)
613     GNUNET_RECLAIM_ATTRIBUTE_list_destroy (rh->rvk_attrs);
614   if (NULL != rh->ns_qe)
615     GNUNET_NAMESTORE_cancel (rh->ns_qe);
616   if (NULL != rh->ns_it)
617     GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
618   GNUNET_free (rh);
619 }
620
621 static int
622 serialize_authz_record (const struct GNUNET_RECLAIM_Ticket *ticket,
623                         const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
624                         struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
625                         char **result)
626 {
627   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
628   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
629   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
630   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
631   struct GNUNET_HashCode new_key_hash;
632   ssize_t enc_size;
633   char *enc_keyinfo;
634   char *buf;
635   char *write_ptr;
636   char attrs_str_len;
637   char *label;
638
639   GNUNET_assert (NULL != attrs->list_head);
640   attrs_str_len = 0;
641   for (le = attrs->list_head; NULL != le; le = le->next) {
642     attrs_str_len += 15 + 1; // TODO propery calculate
643   }
644   buf = GNUNET_malloc (attrs_str_len);
645   write_ptr = buf;
646   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing attributes\n");
647   for (le = attrs->list_head; NULL != le; le = le->next) {
648     label =
649         GNUNET_STRINGS_data_to_string_alloc (&le->claim->id, sizeof (uint64_t));
650     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute to record: %s\n",
651                 label);
652
653     GNUNET_memcpy (write_ptr, label, strlen (label));
654     write_ptr[strlen (label)] = ',';
655     write_ptr += strlen (label) + 1;
656     GNUNET_free (label);
657   }
658   write_ptr--;
659   write_ptr[0] = '\0'; // replace last , with a 0-terminator
660   // ECDH keypair E = eG
661   *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create ();
662   GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey, &ecdh_pubkey);
663   enc_keyinfo = GNUNET_malloc (attrs_str_len);
664   // Derived key K = H(eB)
665   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
666                                                         &ticket->audience,
667                                                         &new_key_hash));
668   create_sym_key_from_ecdh (&new_key_hash, &skey, &iv);
669   enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf, attrs_str_len, &skey, &iv,
670                                               enc_keyinfo);
671   *result =
672       GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + enc_size);
673   GNUNET_memcpy (*result, &ecdh_pubkey,
674                  sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
675   GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
676                  enc_keyinfo, enc_size);
677   GNUNET_free (enc_keyinfo);
678   GNUNET_free (buf);
679   return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey) + enc_size;
680 }
681
682 /**
683  * Send revocation result
684  *
685  * @param rh ticket revocation handle
686  * @param success GNUNET_OK if successful result
687  */
688 static void send_revocation_finished (struct TicketRevocationHandle *rh,
689                                       uint32_t success)
690 {
691   struct GNUNET_MQ_Envelope *env;
692   struct RevokeTicketResultMessage *trm;
693
694   GNUNET_break (TKT_database->delete_ticket (TKT_database->cls, &rh->ticket));
695
696   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
697   trm->id = htonl (rh->r_id);
698   trm->success = htonl (success);
699   GNUNET_MQ_send (rh->client->mq, env);
700   GNUNET_CONTAINER_DLL_remove (rh->client->revoke_op_head,
701                                rh->client->revoke_op_tail, rh);
702 }
703
704 /**
705  * Process ticket from database
706  *
707  * @param cls struct TicketIterationProcResult
708  * @param ticket the ticket
709  * @param attrs the attributes
710  */
711 static void
712 ticket_reissue_proc (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket,
713                      const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs);
714
715 static void revocation_reissue_tickets (struct TicketRevocationHandle *rh);
716
717 static void reissue_next (void *cls)
718 {
719   struct TicketRevocationHandle *rh = cls;
720   revocation_reissue_tickets (rh);
721 }
722
723 static void reissue_ticket_cont (void *cls, int32_t success, const char *emsg)
724 {
725   struct TicketRevocationHandle *rh = cls;
726
727   rh->ns_qe = NULL;
728   if (GNUNET_SYSERR == success) {
729     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", "Unknown Error\n");
730     send_revocation_finished (rh, GNUNET_SYSERR);
731     cleanup_revoke_ticket_handle (rh);
732     return;
733   }
734   rh->offset++;
735   GNUNET_SCHEDULER_add_now (&reissue_next, rh);
736 }
737
738 /**
739  * Process ticket from database
740  *
741  * @param cls struct TicketIterationProcResult
742  * @param ticket the ticket
743  * @param attrs the attributes
744  */
745 static void
746 ticket_reissue_proc (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket,
747                      const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
748 {
749   struct TicketRevocationHandle *rh = cls;
750   struct TicketAttributeUpdateEntry *tue;
751   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
752   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
753   struct GNUNET_GNSRECORD_Data code_record[1];
754   int reissue_ticket;
755   size_t authz_record_len;
756   char *authz_record_data;
757   char *label;
758
759   if (NULL == ticket) {
760     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Iteration done\n");
761     return;
762   }
763
764   if (0 == memcmp (&ticket->audience, &rh->ticket.audience,
765                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) {
766     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
767                 "Do not reissue for this identity.!\n");
768     label = GNUNET_STRINGS_data_to_string_alloc (&rh->ticket.rnd,
769                                                  sizeof (uint64_t));
770     // Delete record
771     rh->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &rh->identity, label, 0,
772                                                 NULL, &reissue_ticket_cont, rh);
773
774     GNUNET_free (label);
775     return;
776   }
777
778   /*
779    * Check if any attribute of this ticket intersects with a rollover attribute
780    */
781   reissue_ticket = GNUNET_NO;
782   for (le = attrs->list_head; NULL != le; le = le->next) {
783     for (tue = rh->attr_updates_head; NULL != tue; tue = tue->next) {
784       if (tue->old_id == le->claim->id) {
785         reissue_ticket = GNUNET_YES;
786         le->claim->id = tue->new_id;
787       }
788     }
789   }
790
791   if (GNUNET_NO == reissue_ticket) {
792     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Skipping ticket.\n");
793
794     rh->offset++;
795     GNUNET_SCHEDULER_add_now (&reissue_next, rh);
796     return;
797   }
798
799   // Create new ABE key for RP
800
801   /* If this is the RP we want to revoke attributes of, the do so */
802
803   // TODO rename function
804   authz_record_len = serialize_authz_record (ticket, attrs, &ecdhe_privkey,
805                                              &authz_record_data);
806   code_record[0].data = authz_record_data;
807   code_record[0].data_size = authz_record_len;
808   code_record[0].expiration_time = GNUNET_TIME_UNIT_DAYS.rel_value_us;
809   code_record[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
810   code_record[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
811
812   label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
813   // Publish record
814   rh->ns_qe = GNUNET_NAMESTORE_records_store (
815       nsh, &rh->identity, label, 1, code_record, &reissue_ticket_cont, rh);
816   GNUNET_free (ecdhe_privkey);
817   GNUNET_free (label);
818   GNUNET_free (authz_record_data);
819 }
820
821 /* Prototype for below function */
822 static void attr_reenc_cont (void *cls, int32_t success, const char *emsg);
823
824 static void revocation_reissue_tickets (struct TicketRevocationHandle *rh)
825 {
826   int ret;
827   /* Done, issue new keys */
828   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
829               "Revocation Phase III: Reissuing Tickets\n");
830   if (GNUNET_SYSERR == (ret = TKT_database->iterate_tickets (
831                             TKT_database->cls, &rh->ticket.identity, GNUNET_NO,
832                             rh->offset, &ticket_reissue_proc, rh))) {
833     GNUNET_break (0);
834   }
835   if (GNUNET_NO == ret) {
836     send_revocation_finished (rh, GNUNET_OK);
837     cleanup_revoke_ticket_handle (rh);
838     return;
839   }
840 }
841
842 /**
843  * Failed to check for attribute
844  */
845 static void check_attr_error (void *cls)
846 {
847   struct TicketRevocationHandle *rh = cls;
848   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
849               "Unable to check for existing attribute\n");
850   rh->ns_qe = NULL;
851   send_revocation_finished (rh, GNUNET_SYSERR);
852   cleanup_revoke_ticket_handle (rh);
853 }
854
855 /**
856  * Revoke next attribte by reencryption with
857  * new ABE master
858  */
859 static void reenc_next_attribute (void *cls);
860
861 /**
862  * Check for existing attribute and overwrite
863  */
864 static void check_attr_cb (void *cls,
865                            const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
866                            const char *label, unsigned int rd_count,
867                            const struct GNUNET_GNSRECORD_Data *rd_old)
868 {
869   struct TicketRevocationHandle *rh = cls;
870   struct TicketAttributeUpdateEntry *tue;
871   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
872   struct GNUNET_GNSRECORD_Data rd[1];
873   char *buf;
874   size_t buf_size;
875   char *new_label;
876
877   rh->ns_qe = NULL;
878   if (1 != rd_count) {
879     le = rh->attrs->list_head;
880     GNUNET_CONTAINER_DLL_remove (rh->attrs->list_head, rh->attrs->list_tail,
881                                  le);
882     GNUNET_assert (NULL != rh->rvk_attrs);
883     GNUNET_CONTAINER_DLL_insert (rh->rvk_attrs->list_head,
884                                  rh->rvk_attrs->list_tail, le);
885     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Re-encrypting next attribute\n");
886     GNUNET_SCHEDULER_add_now (&reenc_next_attribute, rh);
887     return;
888   }
889
890   buf_size =
891       GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (rh->attrs->list_head->claim);
892   buf = GNUNET_malloc (buf_size);
893   rh->attrs->list_head->claim->version++;
894   GNUNET_RECLAIM_ATTRIBUTE_serialize (rh->attrs->list_head->claim, buf);
895   tue = GNUNET_new (struct TicketAttributeUpdateEntry);
896   tue->old_id = rh->attrs->list_head->claim->id;
897   tue->new_id =
898       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
899   GNUNET_CONTAINER_DLL_insert (rh->attr_updates_head, rh->attr_updates_tail,
900                                tue);
901   rh->attrs->list_head->claim->id = tue->new_id;
902   new_label =
903       GNUNET_STRINGS_data_to_string_alloc (&tue->new_id, sizeof (uint64_t));
904   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "New attr id %s\n", new_label);
905   rd[0].data_size = buf_size;
906   rd[0].data = buf;
907   rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
908   rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
909   rd[0].expiration_time = rd_old[0].expiration_time;
910   rh->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &rh->identity, new_label, 1,
911                                               rd, &attr_reenc_cont, rh);
912 }
913
914 /**
915  * Revoke next attribte by reencryption with
916  * new ABE master
917  */
918 static void reenc_next_attribute (void *cls)
919 {
920   struct TicketRevocationHandle *rh = cls;
921   char *label;
922   if (NULL == rh->attrs->list_head) {
923     revocation_reissue_tickets (rh);
924     return;
925   }
926   /* First check if attribute still exists */
927   label = GNUNET_STRINGS_data_to_string_alloc (&rh->attrs->list_head->claim->id,
928                                                sizeof (uint64_t));
929   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name: %s\n",
930               rh->attrs->list_head->claim->name);
931   rh->ns_qe = GNUNET_NAMESTORE_records_lookup (
932       nsh, &rh->identity, label, &check_attr_error, rh, &check_attr_cb, rh);
933   GNUNET_free (label);
934 }
935
936 /**
937  * Namestore callback after revoked attribute
938  * is stored
939  */
940 static void attr_reenc_cont (void *cls, int32_t success, const char *emsg)
941 {
942   struct TicketRevocationHandle *rh = cls;
943   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
944
945   rh->ns_qe = NULL;
946   if (GNUNET_SYSERR == success) {
947     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to reencrypt attribute %s\n",
948                 emsg);
949     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
950     return;
951   }
952   if (NULL == rh->attrs->list_head) {
953     revocation_reissue_tickets (rh);
954     return;
955   }
956   le = rh->attrs->list_head;
957   GNUNET_CONTAINER_DLL_remove (rh->attrs->list_head, rh->attrs->list_tail, le);
958   GNUNET_assert (NULL != rh->rvk_attrs);
959   GNUNET_CONTAINER_DLL_insert (rh->rvk_attrs->list_head,
960                                rh->rvk_attrs->list_tail, le);
961
962   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Re-encrypting next attribute\n");
963   reenc_next_attribute (rh);
964 }
965
966
967 static void process_attributes_to_update (
968     void *cls, const struct GNUNET_RECLAIM_Ticket *ticket,
969     const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs)
970 {
971   struct TicketRevocationHandle *rh = cls;
972
973   rh->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
974   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
975               "Revocation Phase I: Collecting attributes\n");
976   /* Reencrypt all attributes with new key */
977   if (NULL == rh->attrs->list_head) {
978     /* No attributes to reencrypt */
979     send_revocation_finished (rh, GNUNET_OK);
980     cleanup_revoke_ticket_handle (rh);
981     return;
982   } else {
983     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
984                 "Revocation Phase II: Re-encrypting attributes\n");
985     reenc_next_attribute (rh);
986   }
987 }
988
989 static int check_revoke_ticket_message (void *cls,
990                                         const struct RevokeTicketMessage *im)
991 {
992   uint16_t size;
993
994   size = ntohs (im->header.size);
995   if (size <= sizeof (struct RevokeTicketMessage)) {
996     GNUNET_break (0);
997     return GNUNET_SYSERR;
998   }
999   return GNUNET_OK;
1000 }
1001
1002 static void handle_revoke_ticket_message (void *cls,
1003                                           const struct RevokeTicketMessage *rm)
1004 {
1005   struct TicketRevocationHandle *rh;
1006   struct IdpClient *idp = cls;
1007   struct GNUNET_RECLAIM_Ticket *ticket;
1008
1009   rh = GNUNET_new (struct TicketRevocationHandle);
1010   ticket = (struct GNUNET_RECLAIM_Ticket *)&rm[1];
1011   rh->rvk_attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1012   rh->ticket = *ticket;
1013   rh->r_id = ntohl (rm->id);
1014   rh->client = idp;
1015   rh->identity = rm->identity;
1016   GNUNET_CRYPTO_ecdsa_key_get_public (&rh->identity, &rh->ticket.identity);
1017   GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rh);
1018   /**
1019    * TODO replace with GNS storage
1020    */
1021   TKT_database->get_ticket_attributes (TKT_database->cls, &rh->ticket,
1022                                        &process_attributes_to_update, rh);
1023   GNUNET_SERVICE_client_continue (idp->client);
1024 }
1025
1026 static int check_consume_ticket_message (void *cls,
1027                                          const struct ConsumeTicketMessage *cm)
1028 {
1029   uint16_t size;
1030
1031   size = ntohs (cm->header.size);
1032   if (size <= sizeof (struct ConsumeTicketMessage)) {
1033     GNUNET_break (0);
1034     return GNUNET_SYSERR;
1035   }
1036   return GNUNET_OK;
1037 }
1038
1039 static void
1040 consume_result_cb (void *cls,
1041                    const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
1042                    const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1043                    uint32_t success, const char *emsg)
1044 {
1045   struct ConsumeTicketOperation *cop = cls;
1046   struct ConsumeTicketResultMessage *crm;
1047   struct GNUNET_MQ_Envelope *env;
1048   char *data_tmp;
1049   size_t attrs_len;
1050   if (GNUNET_OK != success) {
1051     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
1052   }
1053   attrs_len = GNUNET_RECLAIM_ATTRIBUTE_list_serialize_get_size (attrs);
1054   env = GNUNET_MQ_msg_extra (crm, attrs_len,
1055                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
1056   crm->id = htonl (cop->r_id);
1057   crm->attrs_len = htons (attrs_len);
1058   crm->identity = *identity;
1059   crm->result = htonl (success);
1060   data_tmp = (char *)&crm[1];
1061   GNUNET_RECLAIM_ATTRIBUTE_list_serialize (attrs, data_tmp);
1062   GNUNET_MQ_send (cop->client->mq, env);
1063   GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
1064                                cop->client->consume_op_tail, cop);
1065   GNUNET_free (cop);
1066 }
1067
1068 static void
1069 handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
1070 {
1071   struct ConsumeTicketOperation *cop;
1072   struct GNUNET_RECLAIM_Ticket *ticket;
1073   struct IdpClient *idp = cls;
1074
1075   cop = GNUNET_new (struct ConsumeTicketOperation);
1076   cop->r_id = ntohl (cm->id);
1077   cop->client = idp;
1078   ticket = (struct GNUNET_RECLAIM_Ticket *)&cm[1];
1079   cop->ch =
1080       RECLAIM_TICKETS_consume (&cm->identity, ticket, &consume_result_cb, cop);
1081   GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
1082   GNUNET_SERVICE_client_continue (idp->client);
1083 }
1084
1085 /*****************************************
1086  * Attribute store
1087  *****************************************/
1088
1089 /**
1090  * Cleanup attribute store handle
1091  *
1092  * @param handle handle to clean up
1093  */
1094 static void cleanup_as_handle (struct AttributeStoreHandle *ash)
1095 {
1096   if (NULL != ash->ns_qe)
1097     GNUNET_NAMESTORE_cancel (ash->ns_qe);
1098   if (NULL != ash->claim)
1099     GNUNET_free (ash->claim);
1100   GNUNET_free (ash);
1101 }
1102
1103 static void attr_store_cont (void *cls, int32_t success, const char *emsg)
1104 {
1105   struct AttributeStoreHandle *ash = cls;
1106   struct GNUNET_MQ_Envelope *env;
1107   struct AttributeStoreResultMessage *acr_msg;
1108
1109   ash->ns_qe = NULL;
1110   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
1111                                ash->client->store_op_tail, ash);
1112
1113   if (GNUNET_SYSERR == success) {
1114     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to store attribute %s\n",
1115                 emsg);
1116     cleanup_as_handle (ash);
1117     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1118     return;
1119   }
1120
1121   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1122               "Sending ATTRIBUTE_STORE_RESPONSE message\n");
1123   env = GNUNET_MQ_msg (acr_msg,
1124                        GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE_RESPONSE);
1125   acr_msg->id = htonl (ash->r_id);
1126   acr_msg->op_result = htonl (GNUNET_OK);
1127   GNUNET_MQ_send (ash->client->mq, env);
1128   cleanup_as_handle (ash);
1129 }
1130
1131 /**
1132  * Adds a new attribute
1133  *
1134  * @param cls the AttributeStoreHandle
1135  */
1136 static void attr_store_task (void *cls)
1137 {
1138   struct AttributeStoreHandle *ash = cls;
1139   struct GNUNET_GNSRECORD_Data rd[1];
1140   char *buf;
1141   char *label;
1142   size_t buf_size;
1143
1144   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing attribute\n");
1145   buf_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (ash->claim);
1146   buf = GNUNET_malloc (buf_size);
1147   // Give the ash a new id
1148   ash->claim->id =
1149       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
1150   GNUNET_RECLAIM_ATTRIBUTE_serialize (ash->claim, buf);
1151   label =
1152       GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id, sizeof (uint64_t));
1153   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
1154
1155   rd[0].data_size = buf_size;
1156   rd[0].data = buf;
1157   rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR;
1158   rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1159   rd[0].expiration_time = ash->exp.rel_value_us;
1160   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh, &ash->identity, label, 1,
1161                                                rd, &attr_store_cont, ash);
1162   GNUNET_free (buf);
1163 }
1164
1165 static int
1166 check_attribute_store_message (void *cls,
1167                                const struct AttributeStoreMessage *sam)
1168 {
1169   uint16_t size;
1170
1171   size = ntohs (sam->header.size);
1172   if (size <= sizeof (struct AttributeStoreMessage)) {
1173     GNUNET_break (0);
1174     return GNUNET_SYSERR;
1175   }
1176   return GNUNET_OK;
1177 }
1178
1179 static void
1180 handle_attribute_store_message (void *cls,
1181                                 const struct AttributeStoreMessage *sam)
1182 {
1183   struct AttributeStoreHandle *ash;
1184   struct IdpClient *idp = cls;
1185   size_t data_len;
1186   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_STORE message\n");
1187
1188   data_len = ntohs (sam->attr_len);
1189
1190   ash = GNUNET_new (struct AttributeStoreHandle);
1191   ash->claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize ((char *)&sam[1], data_len);
1192
1193   ash->r_id = ntohl (sam->id);
1194   ash->identity = sam->identity;
1195   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1196   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
1197
1198   GNUNET_SERVICE_client_continue (idp->client);
1199   ash->client = idp;
1200   GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
1201   GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
1202 }
1203
1204 /*************************************************
1205  * Attrubute iteration
1206  *************************************************/
1207
1208 static void cleanup_attribute_iter_handle (struct AttributeIterator *ai)
1209 {
1210   GNUNET_free (ai);
1211 }
1212
1213 static void attr_iter_error (void *cls)
1214 {
1215   struct AttributeIterator *ai = cls;
1216   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
1217   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1218                                ai->client->attr_iter_tail, ai);
1219   cleanup_attribute_iter_handle (ai);
1220   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1221 }
1222
1223 static void attr_iter_finished (void *cls)
1224 {
1225   struct AttributeIterator *ai = cls;
1226   struct GNUNET_MQ_Envelope *env;
1227   struct AttributeResultMessage *arm;
1228
1229   env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1230   arm->id = htonl (ai->request_id);
1231   arm->attr_len = htons (0);
1232   GNUNET_MQ_send (ai->client->mq, env);
1233   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1234                                ai->client->attr_iter_tail, ai);
1235   cleanup_attribute_iter_handle (ai);
1236 }
1237
1238 static void attr_iter_cb (void *cls,
1239                           const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1240                           const char *label, unsigned int rd_count,
1241                           const struct GNUNET_GNSRECORD_Data *rd)
1242 {
1243   struct AttributeIterator *ai = cls;
1244   struct AttributeResultMessage *arm;
1245   struct GNUNET_MQ_Envelope *env;
1246   char *data_tmp;
1247
1248   if (rd_count != 1) {
1249     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1250     return;
1251   }
1252
1253   if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR != rd->record_type) {
1254     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1255     return;
1256   }
1257   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n", label);
1258   env = GNUNET_MQ_msg_extra (arm, rd->data_size,
1259                              GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1260   arm->id = htonl (ai->request_id);
1261   arm->attr_len = htons (rd->data_size);
1262   GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
1263   data_tmp = (char *)&arm[1];
1264   GNUNET_memcpy (data_tmp, rd->data, rd->data_size);
1265   GNUNET_MQ_send (ai->client->mq, env);
1266 }
1267
1268 static void
1269 handle_iteration_start (void *cls,
1270                         const struct AttributeIterationStartMessage *ais_msg)
1271 {
1272   struct IdpClient *idp = cls;
1273   struct AttributeIterator *ai;
1274
1275   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1276               "Received ATTRIBUTE_ITERATION_START message\n");
1277   ai = GNUNET_new (struct AttributeIterator);
1278   ai->request_id = ntohl (ais_msg->id);
1279   ai->client = idp;
1280   ai->identity = ais_msg->identity;
1281
1282   GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
1283   ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (
1284       nsh, &ai->identity, &attr_iter_error, ai, &attr_iter_cb, ai,
1285       &attr_iter_finished, ai);
1286   GNUNET_SERVICE_client_continue (idp->client);
1287 }
1288
1289 static void
1290 handle_iteration_stop (void *cls,
1291                        const struct AttributeIterationStopMessage *ais_msg)
1292 {
1293   struct IdpClient *idp = cls;
1294   struct AttributeIterator *ai;
1295   uint32_t rid;
1296
1297   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
1298               "ATTRIBUTE_ITERATION_STOP");
1299   rid = ntohl (ais_msg->id);
1300   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1301     if (ai->request_id == rid)
1302       break;
1303   if (NULL == ai) {
1304     GNUNET_break (0);
1305     GNUNET_SERVICE_client_drop (idp->client);
1306     return;
1307   }
1308   GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1309   GNUNET_free (ai);
1310   GNUNET_SERVICE_client_continue (idp->client);
1311 }
1312
1313 static void
1314 handle_iteration_next (void *cls,
1315                        const struct AttributeIterationNextMessage *ais_msg)
1316 {
1317   struct IdpClient *idp = cls;
1318   struct AttributeIterator *ai;
1319   uint32_t rid;
1320
1321   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1322               "Received ATTRIBUTE_ITERATION_NEXT message\n");
1323   rid = ntohl (ais_msg->id);
1324   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1325     if (ai->request_id == rid)
1326       break;
1327   if (NULL == ai) {
1328     GNUNET_break (0);
1329     GNUNET_SERVICE_client_drop (idp->client);
1330     return;
1331   }
1332   GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1333   GNUNET_SERVICE_client_continue (idp->client);
1334 }
1335
1336 /******************************************************
1337  * Ticket iteration
1338  ******************************************************/
1339
1340 static void ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
1341 {
1342   struct TicketIteration *ti = cls;
1343   struct GNUNET_MQ_Envelope *env;
1344   struct TicketResultMessage *trm;
1345
1346   if (NULL == ticket) {
1347     /* send empty response to indicate end of list */
1348     env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1349     GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
1350                                  ti->client->ticket_iter_tail, ti);
1351   } else {
1352     env = GNUNET_MQ_msg_extra (trm, sizeof (struct GNUNET_RECLAIM_Ticket),
1353                                GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1354   }
1355   trm->id = htonl (ti->r_id);
1356   GNUNET_MQ_send (ti->client->mq, env);
1357   if (NULL == ticket)
1358     GNUNET_free (ti);
1359 }
1360
1361 static void handle_ticket_iteration_start (
1362     void *cls, const struct TicketIterationStartMessage *tis_msg)
1363 {
1364   struct IdpClient *client = cls;
1365   struct TicketIteration *ti;
1366
1367   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1368               "Received TICKET_ITERATION_START message\n");
1369   ti = GNUNET_new (struct TicketIteration);
1370   ti->r_id = ntohl (tis_msg->id);
1371   ti->client = client;
1372
1373   GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
1374                                client->ticket_iter_tail, ti);
1375   ti->iter =
1376       RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
1377   GNUNET_SERVICE_client_continue (client->client);
1378 }
1379
1380 static void
1381 handle_ticket_iteration_stop (void *cls,
1382                               const struct TicketIterationStopMessage *tis_msg)
1383 {
1384   struct IdpClient *client = cls;
1385   struct TicketIteration *ti;
1386   uint32_t rid;
1387
1388   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received `%s' message\n",
1389               "TICKET_ITERATION_STOP");
1390   rid = ntohl (tis_msg->id);
1391   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1392     if (ti->r_id == rid)
1393       break;
1394   if (NULL == ti) {
1395     GNUNET_break (0);
1396     GNUNET_SERVICE_client_drop (client->client);
1397     return;
1398   }
1399   RECLAIM_TICKETS_iteration_stop (ti->iter);
1400   GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
1401                                client->ticket_iter_tail, ti);
1402   GNUNET_free (ti);
1403   GNUNET_SERVICE_client_continue (client->client);
1404 }
1405
1406 static void
1407 handle_ticket_iteration_next (void *cls,
1408                               const struct TicketIterationNextMessage *tis_msg)
1409 {
1410   struct IdpClient *client = cls;
1411   struct TicketIteration *ti;
1412   uint32_t rid;
1413
1414   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1415               "Received TICKET_ITERATION_NEXT message\n");
1416   rid = ntohl (tis_msg->id);
1417   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1418     if (ti->r_id == rid)
1419       break;
1420   if (NULL == ti) {
1421     GNUNET_break (0);
1422     GNUNET_SERVICE_client_drop (client->client);
1423     return;
1424   }
1425   RECLAIM_TICKETS_iteration_next (ti->iter);
1426   GNUNET_SERVICE_client_continue (client->client);
1427 }
1428
1429 /**
1430  * Main function that will be run
1431  *
1432  * @param cls closure
1433  * @param c the configuration used
1434  * @param server the service handle
1435  */
1436 static void run (void *cls, const struct GNUNET_CONFIGURATION_Handle *c,
1437                  struct GNUNET_SERVICE_Handle *server)
1438 {
1439   char *database;
1440   cfg = c;
1441
1442   if (GNUNET_OK != RECLAIM_TICKETS_init (cfg)) {
1443     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1444                 "Unable to initialized TICKETS subsystem.\n");
1445     GNUNET_SCHEDULER_shutdown ();
1446     return;
1447   }
1448   // Connect to identity and namestore services
1449   nsh = GNUNET_NAMESTORE_connect (cfg);
1450   if (NULL == nsh) {
1451     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1452                          "error connecting to namestore");
1453   }
1454
1455   identity_handle = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
1456   /* Loading DB plugin */
1457   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (
1458                        cfg, "reclaim", "database", &database))
1459     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No database backend configured\n");
1460   GNUNET_asprintf (&db_lib_name, "libgnunet_plugin_reclaim_%s", database);
1461   TKT_database = GNUNET_PLUGIN_load (db_lib_name, (void *)cfg);
1462   GNUNET_free (database);
1463   if (NULL == TKT_database) {
1464     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1465                 "Could not load database backend `%s'\n", db_lib_name);
1466     GNUNET_SCHEDULER_shutdown ();
1467     return;
1468   }
1469
1470   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (
1471                        cfg, "reclaim", "TOKEN_EXPIRATION_INTERVAL",
1472                        &token_expiration_interval)) {
1473     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Time window for zone iteration: %s\n",
1474                 GNUNET_STRINGS_relative_time_to_string (
1475                     token_expiration_interval, GNUNET_YES));
1476   } else {
1477     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1478   }
1479
1480   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1481 }
1482
1483 /**
1484  * Called whenever a client is disconnected.
1485  *
1486  * @param cls closure
1487  * @param client identification of the client
1488  * @param app_ctx @a client
1489  */
1490 static void client_disconnect_cb (void *cls,
1491                                   struct GNUNET_SERVICE_Client *client,
1492                                   void *app_ctx)
1493 {
1494   struct IdpClient *idp = app_ctx;
1495   struct AttributeIterator *ai;
1496   struct TicketIteration *ti;
1497   struct TicketRevocationHandle *rh;
1498   struct TicketIssueOperation *iss;
1499   struct ConsumeTicketOperation *ct;
1500   struct AttributeStoreHandle *as;
1501
1502   // TODO other operations
1503
1504   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
1505
1506   while (NULL != (iss = idp->issue_op_head)) {
1507     GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, idp->issue_op_tail, iss);
1508     GNUNET_free (iss);
1509   }
1510   while (NULL != (ct = idp->consume_op_head)) {
1511     GNUNET_CONTAINER_DLL_remove (idp->consume_op_head, idp->consume_op_tail,
1512                                  ct);
1513     if (NULL != ct->ch)
1514       RECLAIM_TICKETS_consume_cancel (ct->ch);
1515     GNUNET_free (ct);
1516   }
1517   while (NULL != (as = idp->store_op_head)) {
1518     GNUNET_CONTAINER_DLL_remove (idp->store_op_head, idp->store_op_tail, as);
1519     cleanup_as_handle (as);
1520   }
1521
1522   while (NULL != (ai = idp->attr_iter_head)) {
1523     GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1524     cleanup_attribute_iter_handle (ai);
1525   }
1526   while (NULL != (rh = idp->revoke_op_head)) {
1527     GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, idp->revoke_op_tail, rh);
1528     cleanup_revoke_ticket_handle (rh);
1529   }
1530   while (NULL != (ti = idp->ticket_iter_head)) {
1531     GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head, idp->ticket_iter_tail,
1532                                  ti);
1533     GNUNET_free (ti);
1534   }
1535   GNUNET_free (idp);
1536 }
1537
1538 /**
1539  * Add a client to our list of active clients.
1540  *
1541  * @param cls NULL
1542  * @param client client to add
1543  * @param mq message queue for @a client
1544  * @return internal namestore client structure for this client
1545  */
1546 static void *client_connect_cb (void *cls, struct GNUNET_SERVICE_Client *client,
1547                                 struct GNUNET_MQ_Handle *mq)
1548 {
1549   struct IdpClient *idp;
1550   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
1551   idp = GNUNET_new (struct IdpClient);
1552   idp->client = client;
1553   idp->mq = mq;
1554   return idp;
1555 }
1556
1557 /**
1558  * Define "main" method using service macro.
1559  */
1560 GNUNET_SERVICE_MAIN (
1561     "reclaim", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb,
1562     &client_disconnect_cb, NULL,
1563     GNUNET_MQ_hd_var_size (attribute_store_message,
1564                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
1565                            struct AttributeStoreMessage, NULL),
1566     GNUNET_MQ_hd_fixed_size (
1567         iteration_start, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
1568         struct AttributeIterationStartMessage, NULL),
1569     GNUNET_MQ_hd_fixed_size (
1570         iteration_next, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
1571         struct AttributeIterationNextMessage, NULL),
1572     GNUNET_MQ_hd_fixed_size (
1573         iteration_stop, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
1574         struct AttributeIterationStopMessage, NULL),
1575     GNUNET_MQ_hd_var_size (issue_ticket_message,
1576                            GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
1577                            struct IssueTicketMessage, NULL),
1578     GNUNET_MQ_hd_var_size (consume_ticket_message,
1579                            GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
1580                            struct ConsumeTicketMessage, NULL),
1581     GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
1582                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
1583                              struct TicketIterationStartMessage, NULL),
1584     GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
1585                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
1586                              struct TicketIterationNextMessage, NULL),
1587     GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
1588                              GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
1589                              struct TicketIterationStopMessage, NULL),
1590     GNUNET_MQ_hd_var_size (revoke_ticket_message,
1591                            GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
1592                            struct RevokeTicketMessage, NULL),
1593     GNUNET_MQ_handler_end ());
1594 /* end of gnunet-service-reclaim.c */