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