- sscanf type fix
[oweals/gnunet.git] / src / identity-provider / gnunet-service-identity-provider.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
6    it under the terms of the GNU General Public License as published
7    by the Free Software Foundation; either version 3, or (at your
8    option) any later version.
9
10    GNUnet is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with GNUnet; see the file COPYING.  If not, write to the
17    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19    */
20 /**
21  * @author Martin Schanzenbach
22  * @file src/identity-provider/gnunet-service-identity-provider.c
23  * @brief Identity Token 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_statistics_service.h"
34 #include "gnunet_gns_service.h"
35 #include "gnunet_signatures.h"
36 #include "identity_provider.h"
37 #include "identity_token.h"
38 #include <inttypes.h>
39
40 /**
41  * First pass state
42  */
43 #define STATE_INIT 0
44
45 /**
46  * Normal operation state
47  */
48 #define STATE_POST_INIT 1
49
50 /**
51  * Minimum interval between updates
52  */
53 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
54
55 /**
56  * Standard token expiration time
57  */
58 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
59
60 /**
61  * Service state (to detect initial update pass)
62  */
63 static int state;
64
65 /**
66  * Head of ego entry DLL
67  */
68 static struct EgoEntry *ego_head;
69
70 /**
71  * Tail of ego entry DLL
72  */
73 static struct EgoEntry *ego_tail;
74
75 /**
76  * Identity handle
77  */
78 static struct GNUNET_IDENTITY_Handle *identity_handle;
79
80 /**
81  * Token expiration interval
82  */
83 static struct GNUNET_TIME_Relative token_expiration_interval;
84
85 /**
86  * Namestore handle
87  */
88 static struct GNUNET_NAMESTORE_Handle *ns_handle;
89
90 /**
91  * GNS handle
92  */
93 static struct GNUNET_GNS_Handle *gns_handle;
94
95 /**
96  * Namestore qe
97  */
98 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
99
100 /**
101  * Namestore iterator
102  */
103 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
104
105 /**
106  * Timeout task
107  */
108 static struct GNUNET_SCHEDULER_Task * timeout_task;
109
110
111 /**
112  * Update task
113  */
114 static struct GNUNET_SCHEDULER_Task * update_task;
115
116 /**
117  * Timeout for next update pass
118  */
119 static struct GNUNET_TIME_Relative min_rel_exp;
120
121
122 /**
123  * Currently processed token
124  */
125 static struct IdentityToken *token;
126
127 /**
128  * Label for currently processed token
129  */
130 static char* label;
131
132 /**
133  * Scopes for processed token
134  */
135 static char* scopes;
136
137 /**
138  * Expiration for processed token
139  */
140 static uint64_t rd_exp;
141
142 /**
143  * ECDHE Privkey for processed token metadata
144  */
145 static struct GNUNET_CRYPTO_EcdhePrivateKey ecdhe_privkey;
146
147 /**
148  * Handle to the statistics service.
149  */
150 static struct GNUNET_STATISTICS_Handle *stats;
151
152 /**
153  * Notification context, simplifies client broadcasts.
154  */
155 static struct GNUNET_SERVER_NotificationContext *nc;
156
157 /**
158  * Our configuration.
159  */
160 static const struct GNUNET_CONFIGURATION_Handle *cfg;
161
162
163 struct ExchangeHandle
164 {
165
166   /**
167    * Client connection
168    */
169   struct GNUNET_SERVER_Client *client;
170
171   /**
172    * Ticket
173    */
174   struct TokenTicket *ticket;
175
176   /**
177    * Token returned
178    */
179   struct IdentityToken *token;
180
181   /**
182    * LookupRequest
183    */
184   struct GNUNET_GNS_LookupRequest *lookup_request;
185   
186   /**
187    * Audience Key
188    */
189   struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
190
191   /**
192    * Label to return
193    */
194   char *label;
195 };
196
197 struct IssueHandle
198 {
199
200   /**
201    * Client connection
202    */
203   struct GNUNET_SERVER_Client *client;
204
205   /**
206    * Issuer Key
207    */
208   struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
209
210   /**
211    * Issue pubkey
212    */
213   struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
214
215   /**
216    * Audience Key
217    */
218   struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
219
220   /**
221    * Expiration
222    */
223   struct GNUNET_TIME_Absolute expiration;
224
225   /**
226    * Scopes
227    */
228   char *scopes;
229
230   /**
231    * nonce
232    */
233   uint64_t nonce;
234
235   /**
236    * NS iterator
237    */
238   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
239
240   /**
241    * Attribute map
242    */
243   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
244
245   /**
246    * Token
247    */
248   struct IdentityToken *token;
249
250   /**
251    * Ticket
252    */
253   struct TokenTicket *ticket;
254
255   /**
256    * QueueEntry
257    */
258   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
259
260   /**
261    * The label the token is stored under
262    */
263   char *label;
264 };
265
266 /**
267  * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
268  *
269  */
270 struct EgoEntry
271 {
272   /**
273    * DLL
274    */
275   struct EgoEntry *next;
276
277   /**
278    * DLL
279    */
280   struct EgoEntry *prev;
281
282   /**
283    * Ego handle
284    */
285   struct GNUNET_IDENTITY_Ego *ego;
286
287   /**
288    * Attribute map. Contains the attributes as json_t
289    */
290   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
291
292   /**
293    * Attributes are old and should be updated if GNUNET_YES
294    */
295   int attributes_dirty;
296 };
297
298 /**
299  * Continuation for token store call
300  *
301  * @param cls NULL
302  * @param success error code
303  * @param emsg error message
304  */
305 static void
306 store_token_cont (void *cls,
307                   int32_t success,
308                   const char *emsg)
309 {
310   ns_qe = NULL;
311   if (GNUNET_SYSERR == success)
312   {
313     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
314                 "Failed to update token: %s\n",
315                 emsg);
316     return;
317   }
318   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
319 }
320
321
322 /**
323  * This function updates the old token with new attributes,
324  * removes deleted attributes and expiration times.
325  *
326  * @param cls the ego entry
327  * @param tc task context
328  */
329 static void
330 handle_token_update (void *cls,
331                      const struct GNUNET_SCHEDULER_TaskContext *tc)
332 {
333   char *token_metadata;
334   char *write_ptr;
335   char *enc_token_str;
336   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
337   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
338   struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
339   struct EgoEntry *ego_entry = cls;
340   struct GNUNET_GNSRECORD_Data token_record[2];
341   struct GNUNET_HashCode key_hash;
342   struct GNUNET_TIME_Relative token_rel_exp;
343   struct GNUNET_TIME_Relative token_ttl;
344   struct GNUNET_TIME_Absolute token_exp;
345   struct GNUNET_TIME_Absolute token_nbf;
346   struct GNUNET_TIME_Absolute new_exp;
347   struct GNUNET_TIME_Absolute new_iat;
348   struct GNUNET_TIME_Absolute new_nbf;
349   struct IdentityToken *new_token;
350   struct TokenAttr *cur_value;
351   struct TokenAttr *attr;
352   size_t token_metadata_len;
353
354   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
355   GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
356                                       &pub_key);
357
358   //Note: We need the token expiration time here. Not the record expiration
359   //time.
360   //There are two types of tokens: Token that expire on GNS level with
361   //an absolute expiration time. Those are basically tokens that will
362   //be automatically revoked on (record)expiration.
363   //Tokens stored with relative expiration times will expire on the token level (token expiration)
364   //but this service will reissue new tokens that can be retrieved from GNS
365   //automatically.
366
367   for (attr = token->attr_head; NULL != attr; attr = attr->next)
368   {
369     if (0 == strcmp (attr->name, "exp"))
370     {
371       sscanf (attr->val_head->value,
372               "%"SCNu64,
373               &token_exp.abs_value_us);
374     } else if (0 == strcmp (attr->name, "nbf")) {
375       sscanf (attr->val_head->value,
376               "%"SCNu64,
377               &token_nbf.abs_value_us);
378     }
379   }
380   token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
381
382   token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
383   if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
384   {
385     //This token is not yet expired! Save and skip
386     if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
387     {
388       min_rel_exp = token_ttl;
389     }
390     GNUNET_free (token);
391     token = NULL;
392     GNUNET_free (label);
393     label = NULL;
394     GNUNET_free (scopes);
395     scopes = NULL;
396     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
397     return;
398   }
399   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
400               "Token is expired. Create a new one\n");
401   new_token = token_create (&pub_key,
402                             &token->aud_key);
403   new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
404   new_nbf = GNUNET_TIME_absolute_get ();
405   new_iat = new_nbf;
406   for (attr = token->attr_head; NULL != attr; attr = attr->next)
407   {
408     if (0 == strcmp (attr->name, "exp"))
409     {
410       token_add_attr_int (new_token, attr->name, new_exp.abs_value_us);
411     }
412     else if (0 == strcmp (attr->name, "nbf"))
413     {
414       token_add_attr_int (new_token, attr->name, new_nbf.abs_value_us);
415     }
416     else if (0 == strcmp (attr->name, "iat"))
417     {
418       token_add_attr_int (new_token, attr->name, new_iat.abs_value_us);
419     }
420     else if ((0 == strcmp (attr->name, "iss"))
421              || (0 == strcmp (attr->name, "aud")))
422     {
423       //Omit
424     }
425     else if (0 == strcmp (attr->name, "sub"))
426     {
427       token_add_attr (new_token,
428                       attr->name,
429                       attr->val_head->value);
430     }
431     else 
432     {
433       GNUNET_CRYPTO_hash (attr->name,
434                           strlen (attr->name),
435                           &key_hash);
436       //Check if attr still exists. omit of not
437       if (GNUNET_NO != 
438           GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
439                                                   &key_hash))
440       {
441         cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
442                                                        &key_hash);
443         GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
444                                      new_token->attr_tail,
445                                      cur_value);
446       }
447     }
448   }
449
450   // reassemble and set
451   GNUNET_assert (token_serialize (new_token,
452                                   priv_key,
453                                   &new_ecdhe_privkey,
454                                   &enc_token_str));
455
456   token_record[0].data = enc_token_str;
457   token_record[0].data_size = strlen (enc_token_str) + 1;
458   token_record[0].expiration_time = rd_exp; //Old expiration time
459   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
460   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
461
462   //Meta
463   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
464     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
465     + strlen (scopes) + 1; //With 0-Terminator
466   token_metadata = GNUNET_malloc (token_metadata_len);
467   write_ptr = token_metadata;
468   memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
469   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
470   memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
471   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
472   memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
473
474   token_record[1].data = token_metadata;
475   token_record[1].data_size = token_metadata_len;
476   token_record[1].expiration_time = rd_exp;
477   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
478   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
479
480   ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
481                                           priv_key,
482                                           label,
483                                           2,
484                                           token_record,
485                                           &store_token_cont,
486                                           ego_entry);
487   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, ">>> Updating Token w/ %s\n", new_token);
488   token_destroy (new_token);
489   token_destroy (token);
490   GNUNET_free (new_ecdhe_privkey);
491   GNUNET_free (enc_token_str);
492   token = NULL;
493   GNUNET_free (label);
494   label = NULL;
495   GNUNET_free (scopes);
496   scopes = NULL;
497 }
498
499 static void
500 update_identities(void *cls,
501                   const struct GNUNET_SCHEDULER_TaskContext *tc);
502
503 /**
504  *
505  * Cleanup attr_map
506  *
507  * @param cls NULL
508  * @param key the key
509  * @param value the json_t attribute value
510  * @return GNUNET_YES
511  */
512 static int
513 clear_ego_attrs (void *cls,
514                  const struct GNUNET_HashCode *key,
515                  void *value)
516 {
517   struct TokenAttr *attr = value;
518   struct TokenAttrValue *val;
519   struct TokenAttrValue *tmp_val;
520   for (val = attr->val_head; NULL != val;)
521   {
522     tmp_val = val->next;
523     GNUNET_CONTAINER_DLL_remove (attr->val_head,
524                                  attr->val_tail,
525                                  val);
526     GNUNET_free (val->value);
527     GNUNET_free (val);
528     val = tmp_val;
529   }
530   GNUNET_free (attr->name);
531   GNUNET_free (attr);
532
533   return GNUNET_YES;
534 }
535
536 /**
537  *
538  * Update all ID_TOKEN records for an identity and store them
539  *
540  * @param cls the identity entry
541  * @param zone the identity
542  * @param lbl the name of the record
543  * @param rd_count number of records
544  * @param rd record data
545  *
546  */
547 static void
548 token_collect (void *cls,
549                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
550                const char *lbl,
551                unsigned int rd_count,
552                const struct GNUNET_GNSRECORD_Data *rd)
553 {
554   struct EgoEntry *ego_entry = cls;
555   const struct GNUNET_GNSRECORD_Data *token_record;
556   const struct GNUNET_GNSRECORD_Data *token_metadata_record;
557   struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
558
559   if (NULL == lbl)
560   {
561     //Done
562     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
563                 ">>> Updating Ego finished\n");
564     //Clear attribute map for ego
565     GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
566                                            &clear_ego_attrs,
567                                            ego_entry);
568     GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
569     update_task = GNUNET_SCHEDULER_add_now (&update_identities,
570                                             ego_entry->next);
571     return; 
572   }
573
574   //There should be only a single record for a token under a label
575   if (2 != rd_count)
576   {
577     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
578     return;
579   }
580
581   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
582   {
583     token_metadata_record = &rd[0];
584     token_record = &rd[1];
585   } else {
586     token_record = &rd[0];
587     token_metadata_record = &rd[1];
588   }
589   if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
590   {
591     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
592     return;
593   }
594   if (token_record->record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN)
595   {
596     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
597     return;
598   }
599
600   //Get metadata and decrypt token
601   ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
602   aud_key = (struct GNUNET_CRYPTO_EcdsaPublicKey *)&ecdhe_privkey+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey);
603   scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
604
605   token_parse2 (token_record->data,
606                 &ecdhe_privkey,
607                 aud_key,
608                 &token);
609
610   label = GNUNET_strdup (lbl); 
611   rd_exp = token_record->expiration_time;
612
613   GNUNET_SCHEDULER_add_now (&handle_token_update, ego_entry);
614 }
615
616
617 /**
618  *
619  * Collect all ID_ATTR records for an identity and store them
620  *
621  * @param cls the identity entry
622  * @param zone the identity
623  * @param lbl the name of the record
624  * @param rd_count number of records
625  * @param rd record data
626  *
627  */
628 static void
629 attribute_collect (void *cls,
630                    const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
631                    const char *lbl,
632                    unsigned int rd_count,
633                    const struct GNUNET_GNSRECORD_Data *rd)
634 {
635   struct EgoEntry *ego_entry = cls;
636   struct GNUNET_HashCode key;
637   struct TokenAttr *attr;
638   struct TokenAttrValue *val;
639   char *val_str;
640   int i;
641
642   if (NULL == lbl)
643   {
644     //Done
645     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
646                 ">>> Updating Attributes finished\n");
647     ego_entry->attributes_dirty = GNUNET_NO;
648     update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_entry);
649     return;
650   }
651
652   if (0 == rd_count)
653   {
654     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
655     return;
656   }
657   GNUNET_CRYPTO_hash (lbl,
658                       strlen (lbl),
659                       &key);
660   if (1 == rd_count)
661   {
662     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
663     {
664       val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
665                                               rd->data,
666                                               rd->data_size);
667       attr = GNUNET_malloc (sizeof (struct TokenAttr));
668       attr->name = GNUNET_strdup (lbl);
669       val = GNUNET_malloc (sizeof (struct TokenAttrValue));
670       val->value = val_str;
671       GNUNET_CONTAINER_DLL_insert (attr->val_head,
672                                    attr->val_tail,
673                                    val);
674       GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
675                                          &key,
676                                          attr,
677                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
678     }
679
680     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
681     return;
682   }
683
684   attr = GNUNET_malloc (sizeof (struct TokenAttr));
685   attr->name = GNUNET_strdup (lbl);
686   for (i = 0; i < rd_count; i++)
687   {
688     if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
689     {
690       val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
691                                                   rd[i].data,
692                                                   rd[i].data_size);
693       val = GNUNET_malloc (sizeof (struct TokenAttrValue));
694       val->value = val_str;
695       GNUNET_CONTAINER_DLL_insert (attr->val_head,
696                                    attr->val_tail,
697                                    val);
698     }
699   }
700   GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
701                                      &key,
702                                      attr,
703                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
704   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
705   return;
706 }
707
708 /**
709  *
710  * Update identity information for ego. If attribute map is
711  * dirty, first update the attributes.
712  *
713  * @param cls the ego to update
714  * param tc task context
715  *
716  */
717 static void
718 update_identities(void *cls,
719                   const struct GNUNET_SCHEDULER_TaskContext *tc)
720 {
721   struct EgoEntry *next_ego = cls;
722   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
723   update_task = NULL;
724   if (NULL == next_ego)
725   {
726     if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
727       min_rel_exp = MIN_WAIT_TIME;
728     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729                 ">>> Finished. Rescheduling in %d\n",
730                 min_rel_exp.rel_value_us);
731     ns_it = NULL;
732     //finished -> reschedule
733     update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
734                                                 &update_identities,
735                                                 ego_head);
736     min_rel_exp.rel_value_us = 0;
737     return;
738   }
739   priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
740   if (GNUNET_YES == next_ego->attributes_dirty)
741   {
742     //Starting over. We must update the Attributes for they might have changed.
743     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
744                                                    priv_key,
745                                                    &attribute_collect,
746                                                    next_ego);
747
748   }
749   else
750   {
751     //Ego will be dirty next time
752     next_ego->attributes_dirty = GNUNET_YES;
753     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
754                                                    priv_key,
755                                                    &token_collect,
756                                                    next_ego);
757   }
758 }
759
760
761
762 /**
763  * Function called initially to start update task
764  */
765 static void
766 init_cont ()
767 {
768   GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
769   //Initially iterate all itenties and refresh all tokens
770   update_task = GNUNET_SCHEDULER_add_now (&update_identities, ego_head);
771 }
772
773 /**
774  * Initial ego collection function.
775  *
776  * @param cls NULL
777  * @param ego ego
778  * @param ctx context
779  * @param identifier ego name
780  */
781 static void
782 list_ego (void *cls,
783           struct GNUNET_IDENTITY_Ego *ego,
784           void **ctx,
785           const char *identifier)
786 {
787   struct EgoEntry *new_entry;
788   if ((NULL == ego) && (STATE_INIT == state))
789   {
790     state = STATE_POST_INIT;
791     init_cont ();
792     return;
793   }
794   if (STATE_INIT == state) {
795     new_entry = GNUNET_malloc (sizeof (struct EgoEntry));
796     new_entry->ego = ego;
797     new_entry->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
798                                                                 GNUNET_NO);
799     new_entry->attributes_dirty = GNUNET_YES;
800     GNUNET_CONTAINER_DLL_insert_tail(ego_head, ego_tail, new_entry);
801   }
802 }
803
804 /**
805  * Cleanup task
806  */
807 static void
808 cleanup()
809 {
810   struct EgoEntry *ego_entry;
811   struct EgoEntry *ego_tmp;
812
813   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
814               "Cleaning up\n");
815   if (NULL != nc)
816   {
817     GNUNET_SERVER_notification_context_destroy (nc);
818     nc = NULL;
819   }
820   if (NULL != stats)
821   {
822     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
823     stats = NULL;
824   }
825
826   if (NULL != timeout_task)
827     GNUNET_SCHEDULER_cancel (timeout_task);
828   if (NULL != update_task)
829     GNUNET_SCHEDULER_cancel (update_task);
830   if (NULL != identity_handle)
831     GNUNET_IDENTITY_disconnect (identity_handle);
832   if (NULL != gns_handle)
833     GNUNET_GNS_disconnect (gns_handle);
834   if (NULL != ns_it)
835     GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
836   if (NULL != ns_qe)
837     GNUNET_NAMESTORE_cancel (ns_qe);
838   if (NULL != ns_handle)
839     GNUNET_NAMESTORE_disconnect (ns_handle);
840   if (NULL != token)
841     GNUNET_free (token);
842   if (NULL != label)
843     GNUNET_free (label);
844
845   for (ego_entry = ego_head;
846        NULL != ego_entry;)
847   {
848     ego_tmp = ego_entry;
849     if (0 != GNUNET_CONTAINER_multihashmap_size (ego_tmp->attr_map))
850     {
851       GNUNET_CONTAINER_multihashmap_iterate (ego_tmp->attr_map,
852                                              &clear_ego_attrs,
853                                              ego_tmp);
854
855     }
856     GNUNET_CONTAINER_multihashmap_destroy (ego_tmp->attr_map);
857     ego_entry = ego_entry->next;
858     GNUNET_free (ego_tmp);
859   }
860 }
861
862 /**
863  * Shutdown task
864  *
865  * @param cls NULL
866  * @param tc task context
867  */
868 static void
869 do_shutdown (void *cls,
870              const struct GNUNET_SCHEDULER_TaskContext *tc)
871 {
872   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
873               "Shutting down...\n");
874   cleanup();
875 }
876
877
878 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
879 create_exchange_result_message (const char* token,
880                                 const char* label,
881                                 uint64_t ticket_nonce)
882 {
883   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
884   uint16_t token_len = strlen (token) + 1;
885   erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage) 
886                        + token_len);
887   erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
888   erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage) 
889                             + token_len);
890   erm->ticket_nonce = htonl (ticket_nonce);
891   memcpy (&erm[1], token, token_len);
892   return erm;
893 }
894
895
896 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
897 create_issue_result_message (const char* label,
898                              const char* ticket,
899                              const char* token)
900 {
901   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
902   char *tmp_str;
903
904   irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) 
905                        + strlen (label) + 1
906                        + strlen (ticket) + 1
907                        + strlen (token) + 1);
908   irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
909   irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage) 
910                             + strlen (label) + 1
911                             + strlen (ticket) + 1
912                             + strlen (token) + 1);
913   GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
914   memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
915   GNUNET_free (tmp_str);
916   return irm;
917 }
918
919 static void
920 cleanup_issue_handle (struct IssueHandle *handle)
921 {
922   if (NULL != handle->attr_map)
923     GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
924   if (NULL != handle->scopes)
925     GNUNET_free (handle->scopes);
926   if (NULL != handle->token)
927    token_destroy (handle->token);
928   if (NULL != handle->ticket)
929     ticket_destroy (handle->ticket);
930   if (NULL != handle->label)
931     GNUNET_free (handle->label);
932   GNUNET_free (handle);
933 }
934
935 static void
936 store_token_issue_cont (void *cls,
937                         int32_t success,
938                         const char *emsg)
939 {
940   struct IssueHandle *handle = cls;
941   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
942   char *ticket_str;
943   char *token_str;
944   handle->ns_qe = NULL;
945   if (GNUNET_SYSERR == success)
946   {
947     cleanup_issue_handle (handle);
948     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
949                 "Unknown Error\n");
950     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
951     return;
952   }
953   if (GNUNET_OK != ticket_serialize (handle->ticket,
954                                      &handle->iss_key,
955                                      &ticket_str))
956   {
957     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
958                 "Error serializing ticket\n");
959     cleanup_issue_handle (handle);
960     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); 
961     return;
962   }
963   if (GNUNET_OK != token_to_string (handle->token,
964                                     &handle->iss_key,
965                                     &token_str))
966   {
967     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
968                 "Error serializing token\n");
969     GNUNET_free (ticket_str);
970     cleanup_issue_handle (handle);
971     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL); 
972     return;
973   }
974   irm = create_issue_result_message (handle->label, ticket_str, token_str);
975   GNUNET_SERVER_notification_context_unicast (nc,
976                                               handle->client,
977                                               &irm->header,
978                                               GNUNET_NO);
979   GNUNET_SERVER_client_set_user_context (handle->client, NULL);
980   cleanup_issue_handle (handle);
981   GNUNET_free (irm);
982   GNUNET_free (ticket_str);
983   GNUNET_free (token_str);
984 }
985
986 /**
987  * Build a GNUid token for identity
988  * @param handle the handle
989  * @param ego_entry the ego to build the token for
990  * @param name name of the ego
991  * @param token_aud token audience
992  * @param token the resulting gnuid token
993  * @return identifier string of token (label)
994  */
995 static void
996 sign_and_return_token (void *cls,
997                        const struct GNUNET_SCHEDULER_TaskContext *tc)
998 {
999   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1000   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1001   struct IssueHandle *handle = cls;
1002   struct GNUNET_GNSRECORD_Data token_record[2];
1003   char *nonce_str;
1004   char *enc_token_str;
1005   char *token_metadata;
1006   char* write_ptr;
1007   uint64_t time;
1008   uint64_t exp_time;
1009   size_t token_metadata_len;
1010
1011   //Remote nonce 
1012   nonce_str = NULL;
1013   GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1014   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1015
1016   GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1017                                       &pub_key);
1018   handle->ticket = ticket_create (handle->nonce,
1019                                   &pub_key,
1020                                   handle->label,
1021                                   &handle->aud_key);
1022
1023   time = GNUNET_TIME_absolute_get().abs_value_us;
1024   exp_time = time + token_expiration_interval.rel_value_us;
1025
1026   token_add_attr_int (handle->token, "nbf", time);
1027   token_add_attr_int (handle->token, "iat", time);
1028   token_add_attr_int (handle->token, "exp", exp_time);
1029   token_add_attr (handle->token, "nonce", nonce_str);
1030
1031   //Token in a serialized encrypted format 
1032   GNUNET_assert (token_serialize (handle->token,
1033                                   &handle->iss_key,
1034                                   &ecdhe_privkey,
1035                                   &enc_token_str));
1036
1037   //Token record E,E_K (Token)
1038   token_record[0].data = enc_token_str;
1039   token_record[0].data_size = strlen (enc_token_str) + 1;
1040   token_record[0].expiration_time = exp_time;
1041   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1042   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1043
1044
1045   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1046     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1047     + strlen (handle->scopes) + 1; //With 0-Terminator
1048   token_metadata = GNUNET_malloc (token_metadata_len);
1049   write_ptr = token_metadata;
1050   memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1051   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1052   memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1053   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1054   memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1055
1056   token_record[1].data = token_metadata;
1057   token_record[1].data_size = token_metadata_len;
1058   token_record[1].expiration_time = exp_time;
1059   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1060   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1061
1062   //Persist token
1063   handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1064                                                   &handle->iss_key,
1065                                                   handle->label,
1066                                                   2,
1067                                                   token_record,
1068                                                   &store_token_issue_cont,
1069                                                   handle);
1070   GNUNET_free (ecdhe_privkey);
1071   GNUNET_free (nonce_str);
1072   GNUNET_free (enc_token_str);
1073   GNUNET_free (token_metadata);
1074 }
1075
1076 /**
1077  * Collect attributes for token
1078  */
1079 static void
1080 attr_collect (void *cls,
1081               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1082               const char *label,
1083               unsigned int rd_count,
1084               const struct GNUNET_GNSRECORD_Data *rd)
1085 {
1086   int i;
1087   char* data;
1088   struct IssueHandle *handle = cls;
1089   struct GNUNET_HashCode key;
1090
1091   if (NULL == label)
1092   {
1093     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1094     handle->ns_it = NULL;
1095     GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1096     return;
1097   }
1098
1099   GNUNET_CRYPTO_hash (label,
1100                       strlen (label),
1101                       &key);
1102
1103   if (0 == rd_count ||
1104       ( (NULL != handle->attr_map) &&
1105         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1106                                                                &key))
1107       )
1108      )
1109   {
1110     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1111     return;
1112   }
1113
1114   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1115
1116   if (1 == rd_count)
1117   {
1118     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1119     {
1120       data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1121                                                rd->data,
1122                                                rd->data_size);
1123       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1124       token_add_attr (handle->token,
1125                       label,
1126                       data);
1127       GNUNET_free (data);
1128     }
1129     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1130     return;
1131   }
1132
1133   i = 0;
1134   for (; i < rd_count; i++)
1135   {
1136     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1137     {
1138       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1139                                                rd[i].data,
1140                                                rd[i].data_size);
1141       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1142       token_add_attr (handle->token, label, data);
1143       GNUNET_free (data);
1144     }
1145   }
1146
1147   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1148 }
1149
1150 static void
1151 cleanup_exchange_handle (struct ExchangeHandle *handle)
1152 {
1153   if (NULL != handle->ticket) 
1154     ticket_destroy (handle->ticket);
1155   if (NULL != handle->token)
1156     token_destroy (handle->token);
1157   GNUNET_free (handle);
1158 }
1159
1160 static void
1161 process_lookup_result (void *cls, uint32_t rd_count,
1162                        const struct GNUNET_GNSRECORD_Data *rd)
1163 {
1164   struct ExchangeHandle *handle = cls;
1165   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1166   char* token_str;
1167   char* record_str;
1168
1169   handle->lookup_request = NULL;
1170   if (2 != rd_count)
1171   {
1172     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1173                 "Number of tokens %d != 2.",
1174                 rd_count);
1175     cleanup_exchange_handle (handle);
1176     GNUNET_SCHEDULER_add_now (&do_shutdown, handle);
1177     return;
1178   }
1179
1180   record_str = 
1181     GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1182                                       rd->data,
1183                                       rd->data_size);
1184
1185   //Decrypt and parse
1186   GNUNET_assert (GNUNET_OK ==  token_parse (record_str,
1187                                             &handle->aud_privkey,
1188                                             &handle->token));
1189
1190   //Readable
1191   GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1192                                                &handle->aud_privkey,
1193                                                &token_str));
1194
1195   erm = create_exchange_result_message (token_str,
1196                                         handle->label,
1197                                         handle->ticket->payload->nonce);
1198   GNUNET_SERVER_notification_context_unicast (nc,
1199                                               handle->client,
1200                                               &erm->header,
1201                                               GNUNET_NO);
1202   GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1203
1204   cleanup_exchange_handle (handle);
1205   GNUNET_free (record_str);
1206   GNUNET_free (token_str);
1207   GNUNET_free (erm);
1208
1209 }
1210
1211
1212
1213 /**
1214  *
1215  * Handler for exchange message
1216  *
1217  * @param cls unused
1218  * @param client who sent the message
1219  * @param message the message
1220  */
1221 static void
1222 handle_exchange_message (void *cls,
1223                          struct GNUNET_SERVER_Client *client,
1224                          const struct GNUNET_MessageHeader *message)
1225 {
1226   const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1227   struct ExchangeHandle *xchange_handle;
1228   uint16_t size;
1229   const char *ticket;
1230   char *lookup_query;
1231
1232   size = ntohs (message->size);
1233   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1234   {
1235     GNUNET_break (0);
1236     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1237     return;
1238   }
1239   em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1240   ticket = (const char *) &em[1];
1241   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1242               "Received EXCHANGE of `%s' from client\n",
1243               ticket);
1244   xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1245   xchange_handle->aud_privkey = em->aud_privkey;
1246
1247   if (GNUNET_SYSERR == ticket_parse (ticket,
1248                                      &xchange_handle->aud_privkey,
1249                                      &xchange_handle->ticket))
1250   {
1251     GNUNET_free (xchange_handle);
1252     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1253     return;
1254   }
1255   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1256               xchange_handle->ticket->payload->label);
1257   GNUNET_asprintf (&lookup_query,
1258                    "%s.gnu",
1259                    xchange_handle->ticket->payload->label);
1260   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1261   GNUNET_SERVER_notification_context_add (nc, client);
1262   GNUNET_SERVER_client_set_user_context (client, xchange_handle);
1263   xchange_handle->client = client;
1264   xchange_handle->lookup_request = GNUNET_GNS_lookup (gns_handle,
1265                                                       lookup_query,
1266                                                       &xchange_handle->ticket->payload->identity_key,
1267                                                       GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1268                                                       GNUNET_GNS_LO_LOCAL_MASTER,
1269                                                       NULL,
1270                                                       &process_lookup_result,
1271                                                       xchange_handle);
1272   GNUNET_free (lookup_query);
1273
1274 }
1275
1276
1277 /**
1278  *
1279  * Look for existing token
1280  *
1281  * @param cls the identity entry
1282  * @param zone the identity
1283  * @param lbl the name of the record
1284  * @param rd_count number of records
1285  * @param rd record data
1286  *
1287  */
1288 static void
1289 find_existing_token (void *cls,
1290                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1291                      const char *lbl,
1292                      unsigned int rd_count,
1293                      const struct GNUNET_GNSRECORD_Data *rd)
1294 {
1295   struct IssueHandle *handle = cls;
1296   const struct GNUNET_GNSRECORD_Data *token_metadata_record;
1297   struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
1298   struct GNUNET_HashCode key;
1299   int scope_count_token;
1300   uint64_t rnd_key;
1301   char *scope;
1302   char *tmp_scopes;
1303
1304   if (NULL == lbl)
1305   {
1306     //Done
1307     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1308                 ">>> No existing token found\n");
1309     //Label
1310     rnd_key = 
1311       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1312                                 UINT64_MAX);
1313     GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1314                                   sizeof (uint64_t),
1315                                   &handle->label);
1316     handle->ns_it = NULL;
1317     handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1318                                                            &handle->iss_key,
1319                                                            &attr_collect,
1320                                                            handle);
1321     return; 
1322   }
1323
1324   //There should be only a single record for a token under a label
1325   if (2 != rd_count)
1326   {
1327     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1328     return;
1329   }
1330
1331   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1332   {
1333     token_metadata_record = &rd[0];
1334   } else {
1335     token_metadata_record = &rd[1];
1336   }
1337   if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1338   {
1339     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1340     return;
1341   }
1342   ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
1343   aud_key = 
1344     (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
1345   tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1346
1347   if (0 != memcmp (aud_key, &handle->aud_key,
1348                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1349   {
1350     char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
1351                                                       sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1352     //Audience does not match!
1353     char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
1354                                                   token_metadata_record->data,
1355                                                   token_metadata_record->data_size);
1356     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1357                 "Token does not match audience %s vs %s. Moving on\n",
1358                 tmp2,
1359                 tmp);
1360     GNUNET_free (tmp_scopes);
1361     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1362     return;
1363   }
1364
1365   scope = strtok (tmp_scopes, ",");
1366   scope_count_token = 0;
1367   while (NULL != scope)
1368   {
1369     GNUNET_CRYPTO_hash (scope,
1370                         strlen (scope),
1371                         &key);
1372
1373     if ((NULL != handle->attr_map) &&
1374         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
1375     {
1376       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1377                   "Issued token does not include `%s'. Moving on\n", scope);
1378       GNUNET_free (tmp_scopes);
1379       GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1380       return;
1381     }
1382     scope_count_token++;
1383     scope = strtok (NULL, ",");
1384   }
1385   GNUNET_free (tmp_scopes);
1386   //All scopes in token are also in request. Now
1387   //Check length
1388   if (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token)
1389   {
1390     //We have an existing token
1391     handle->label = GNUNET_strdup (lbl);
1392     handle->ns_it = NULL;
1393     handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1394                                                            &handle->iss_key,
1395                                                            &attr_collect,
1396                                                            handle);
1397
1398     return;
1399   }
1400   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1401               "Nuber of attributes in token do not match request\n");
1402   //No luck
1403   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1404 }
1405
1406
1407 /**
1408  *
1409  * Handler for issue message
1410  *
1411  * @param cls unused
1412  * @param client who sent the message
1413  * @param message the message
1414  */
1415 static void
1416 handle_issue_message (void *cls,
1417                       struct GNUNET_SERVER_Client *client,
1418                       const struct GNUNET_MessageHeader *message)
1419 {
1420   const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1421   const char *scopes;
1422
1423   uint16_t size;
1424   char *scopes_tmp;
1425   char *scope;
1426   struct GNUNET_HashCode key;
1427   struct IssueHandle *issue_handle;
1428
1429   size = ntohs (message->size);
1430   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1431   {
1432     GNUNET_break (0);
1433     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1434     return;
1435   }
1436   im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1437   scopes = (const char *) &im[1];
1438   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1439               "Received ISSUE of `%s' from client\n",
1440               scope);
1441   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1442   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1443                                                                  GNUNET_NO);
1444   scopes_tmp = GNUNET_strdup (scopes);
1445   scope = strtok(scopes_tmp, ",");
1446   for (; NULL != scope; scope = strtok (NULL, ","))
1447   {
1448     GNUNET_CRYPTO_hash (scope,
1449                         strlen (scope),
1450                         &key);
1451     GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1452                                        &key,
1453                                        scope,
1454                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1455   }
1456   GNUNET_free (scopes_tmp);
1457
1458   issue_handle->aud_key = im->aud_key;
1459   issue_handle->iss_key = im->iss_key;
1460   GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1461                                       &issue_handle->iss_pkey);
1462   issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1463   issue_handle->nonce = ntohl (im->nonce);
1464   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1465   GNUNET_SERVER_notification_context_add (nc, client);
1466   GNUNET_SERVER_client_set_user_context (client, issue_handle);
1467   issue_handle->client = client;
1468   issue_handle->scopes = GNUNET_strdup (scopes);
1469   issue_handle->token = token_create (&issue_handle->iss_pkey,
1470                                       &issue_handle->aud_key);
1471
1472   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1473                                                                &im->iss_key,
1474                                                                &find_existing_token,
1475                                                                issue_handle);
1476 }
1477
1478 /**
1479  * Main function that will be run
1480  *
1481  * @param cls closure
1482  * @param args remaining command-line arguments
1483  * @param cfgfile name of the configuration file used (for saving, can be NULL)
1484  * @param c configuration
1485  */
1486 static void
1487 run (void *cls, 
1488      struct GNUNET_SERVER_Handle *server,
1489      const struct GNUNET_CONFIGURATION_Handle *c)
1490 {
1491   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1492     {&handle_issue_message, NULL,
1493       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1494     {&handle_exchange_message, NULL,
1495       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1496     {NULL, NULL, 0, 0}
1497   };
1498
1499   cfg = c;
1500
1501   stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1502   GNUNET_SERVER_add_handlers (server, handlers);
1503   nc = GNUNET_SERVER_notification_context_create (server, 1);
1504
1505   //Connect to identity and namestore services
1506   ns_handle = GNUNET_NAMESTORE_connect (cfg);
1507   if (NULL == ns_handle)
1508   {
1509     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1510   }
1511
1512   gns_handle = GNUNET_GNS_connect (cfg);
1513   if (NULL == gns_handle)
1514   {
1515     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1516   }
1517
1518   identity_handle = GNUNET_IDENTITY_connect (cfg,
1519                                              &list_ego,
1520                                              NULL);
1521
1522   if (GNUNET_OK == 
1523       GNUNET_CONFIGURATION_get_value_time (cfg,
1524                                            "identity-provider",
1525                                            "TOKEN_EXPIRATION_INTERVAL",
1526                                            &token_expiration_interval))
1527   {
1528     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1529                 "Time window for zone iteration: %s\n",
1530                 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1531                                                         GNUNET_YES));
1532   } else {
1533     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1534   }
1535
1536   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1537                                 &do_shutdown, NULL);
1538 }
1539
1540
1541 /**
1542  *
1543  * The main function
1544  *
1545  * @param argc number of arguments from the cli
1546  * @param argv command line arguments
1547  * @return 0 ok, 1 on error
1548  *
1549  */
1550 int
1551 main (int argc, char *const *argv)
1552 {
1553   return  (GNUNET_OK ==
1554            GNUNET_SERVICE_run (argc, argv, "identity-provider",
1555                                GNUNET_SERVICE_OPTION_NONE,
1556                                &run, NULL)) ? 0 : 1;
1557 }
1558
1559 /* end of gnunet-rest-server.c */