Update jsonapi to current specs, refactor
[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  * 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  */
327 static void
328 handle_token_update (void *cls)
329 {
330   char *token_metadata;
331   char *write_ptr;
332   char *enc_token_str;
333   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
334   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
335   struct GNUNET_CRYPTO_EcdhePrivateKey *new_ecdhe_privkey;
336   struct EgoEntry *ego_entry = cls;
337   struct GNUNET_GNSRECORD_Data token_record[2];
338   struct GNUNET_HashCode key_hash;
339   struct GNUNET_TIME_Relative token_rel_exp;
340   struct GNUNET_TIME_Relative token_ttl;
341   struct GNUNET_TIME_Absolute token_exp;
342   struct GNUNET_TIME_Absolute token_nbf;
343   struct GNUNET_TIME_Absolute new_exp;
344   struct GNUNET_TIME_Absolute new_iat;
345   struct GNUNET_TIME_Absolute new_nbf;
346   struct IdentityToken *new_token;
347   struct TokenAttr *cur_value;
348   struct TokenAttr *attr;
349   size_t token_metadata_len;
350
351   priv_key = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
352   GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego,
353                                       &pub_key);
354
355   //Note: We need the token expiration time here. Not the record expiration
356   //time.
357   //There are two types of tokens: Token that expire on GNS level with
358   //an absolute expiration time. Those are basically tokens that will
359   //be automatically revoked on (record)expiration.
360   //Tokens stored with relative expiration times will expire on the token level (token expiration)
361   //but this service will reissue new tokens that can be retrieved from GNS
362   //automatically.
363
364   for (attr = token->attr_head; NULL != attr; attr = attr->next)
365   {
366     if (0 == strcmp (attr->name, "exp"))
367     {
368       sscanf (attr->val_head->value,
369               "%"SCNu64,
370               &token_exp.abs_value_us);
371     } else if (0 == strcmp (attr->name, "nbf")) {
372       sscanf (attr->val_head->value,
373               "%"SCNu64,
374               &token_nbf.abs_value_us);
375     }
376   }
377   token_rel_exp = GNUNET_TIME_absolute_get_difference (token_nbf, token_exp);
378
379   token_ttl = GNUNET_TIME_absolute_get_remaining (token_exp);
380   if (0 != GNUNET_TIME_absolute_get_remaining (token_exp).rel_value_us)
381   {
382     //This token is not yet expired! Save and skip
383     if (min_rel_exp.rel_value_us > token_ttl.rel_value_us)
384     {
385       min_rel_exp = token_ttl;
386     }
387     GNUNET_free (token);
388     token = NULL;
389     GNUNET_free (label);
390     label = NULL;
391     GNUNET_free (scopes);
392     scopes = NULL;
393     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
394     return;
395   }
396   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
397               "Token is expired. Create a new one\n");
398   new_token = token_create (&pub_key,
399                             &token->aud_key);
400   new_exp = GNUNET_TIME_relative_to_absolute (token_rel_exp);
401   new_nbf = GNUNET_TIME_absolute_get ();
402   new_iat = new_nbf;
403   for (attr = token->attr_head; NULL != attr; attr = attr->next)
404   {
405     if (0 == strcmp (attr->name, "exp"))
406     {
407       token_add_attr_int (new_token, attr->name, new_exp.abs_value_us);
408     }
409     else if (0 == strcmp (attr->name, "nbf"))
410     {
411       token_add_attr_int (new_token, attr->name, new_nbf.abs_value_us);
412     }
413     else if (0 == strcmp (attr->name, "iat"))
414     {
415       token_add_attr_int (new_token, attr->name, new_iat.abs_value_us);
416     }
417     else if ((0 == strcmp (attr->name, "iss"))
418              || (0 == strcmp (attr->name, "aud")))
419     {
420       //Omit
421     }
422     else if (0 == strcmp (attr->name, "sub"))
423     {
424       token_add_attr (new_token,
425                       attr->name,
426                       attr->val_head->value);
427     }
428     else
429     {
430       GNUNET_CRYPTO_hash (attr->name,
431                           strlen (attr->name),
432                           &key_hash);
433       //Check if attr still exists. omit of not
434       if (GNUNET_NO !=
435           GNUNET_CONTAINER_multihashmap_contains (ego_entry->attr_map,
436                                                   &key_hash))
437       {
438         cur_value = GNUNET_CONTAINER_multihashmap_get (ego_entry->attr_map,
439                                                        &key_hash);
440         GNUNET_CONTAINER_DLL_insert (new_token->attr_head,
441                                      new_token->attr_tail,
442                                      cur_value);
443       }
444     }
445   }
446
447   // reassemble and set
448   GNUNET_assert (token_serialize (new_token,
449                                   priv_key,
450                                   &new_ecdhe_privkey,
451                                   &enc_token_str));
452
453   token_record[0].data = enc_token_str;
454   token_record[0].data_size = strlen (enc_token_str) + 1;
455   token_record[0].expiration_time = rd_exp; //Old expiration time
456   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
457   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
458
459   //Meta
460   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
461     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
462     + strlen (scopes) + 1; //With 0-Terminator
463   token_metadata = GNUNET_malloc (token_metadata_len);
464   write_ptr = token_metadata;
465   memcpy (token_metadata, new_ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
466   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
467   memcpy (write_ptr, &token->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
468   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
469   memcpy (write_ptr, scopes, strlen (scopes) + 1); //with 0-Terminator;
470
471   token_record[1].data = token_metadata;
472   token_record[1].data_size = token_metadata_len;
473   token_record[1].expiration_time = rd_exp;
474   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
475   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
476
477   ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
478                                           priv_key,
479                                           label,
480                                           2,
481                                           token_record,
482                                           &store_token_cont,
483                                           ego_entry);
484   token_destroy (new_token);
485   token_destroy (token);
486   GNUNET_free (new_ecdhe_privkey);
487   GNUNET_free (enc_token_str);
488   token = NULL;
489   GNUNET_free (label);
490   label = NULL;
491   GNUNET_free (scopes);
492   scopes = NULL;
493 }
494
495
496 static void
497 update_identities(void *cls);
498
499
500 /**
501  *
502  * Cleanup attr_map
503  *
504  * @param cls NULL
505  * @param key the key
506  * @param value the json_t attribute value
507  * @return #GNUNET_YES
508  */
509 static int
510 clear_ego_attrs (void *cls,
511                  const struct GNUNET_HashCode *key,
512                  void *value)
513 {
514   struct TokenAttr *attr = value;
515   struct TokenAttrValue *val;
516   struct TokenAttrValue *tmp_val;
517   for (val = attr->val_head; NULL != val;)
518   {
519     tmp_val = val->next;
520     GNUNET_CONTAINER_DLL_remove (attr->val_head,
521                                  attr->val_tail,
522                                  val);
523     GNUNET_free (val->value);
524     GNUNET_free (val);
525     val = tmp_val;
526   }
527   GNUNET_free (attr->name);
528   GNUNET_free (attr);
529
530   return GNUNET_YES;
531 }
532
533
534 /**
535  *
536  * Update all ID_TOKEN records for an identity and store them
537  *
538  * @param cls the identity entry
539  * @param zone the identity
540  * @param lbl the name of the record
541  * @param rd_count number of records
542  * @param rd record data
543  */
544 static void
545 token_collect (void *cls,
546                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
547                const char *lbl,
548                unsigned int rd_count,
549                const struct GNUNET_GNSRECORD_Data *rd)
550 {
551   struct EgoEntry *ego_entry = cls;
552   const struct GNUNET_GNSRECORD_Data *token_record;
553   const struct GNUNET_GNSRECORD_Data *token_metadata_record;
554   struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
555
556   if (NULL == lbl)
557   {
558     //Done
559     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560                 ">>> Updating Ego finished\n");
561     //Clear attribute map for ego
562     GNUNET_CONTAINER_multihashmap_iterate (ego_entry->attr_map,
563                                            &clear_ego_attrs,
564                                            ego_entry);
565     GNUNET_CONTAINER_multihashmap_clear (ego_entry->attr_map);
566     update_task = GNUNET_SCHEDULER_add_now (&update_identities,
567                                             ego_entry->next);
568     return;
569   }
570
571   //There should be only a single record for a token under a label
572   if (2 != rd_count)
573   {
574     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
575     return;
576   }
577
578   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
579   {
580     token_metadata_record = &rd[0];
581     token_record = &rd[1];
582   }
583   else
584   {
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,
613                             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,
649                                             ego_entry);
650     return;
651   }
652
653   if (0 == rd_count)
654   {
655     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
656     return;
657   }
658   GNUNET_CRYPTO_hash (lbl,
659                       strlen (lbl),
660                       &key);
661   if (1 == rd_count)
662   {
663     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
664     {
665       val_str = GNUNET_GNSRECORD_value_to_string (rd->record_type,
666                                               rd->data,
667                                               rd->data_size);
668       attr = GNUNET_malloc (sizeof (struct TokenAttr));
669       attr->name = GNUNET_strdup (lbl);
670       val = GNUNET_malloc (sizeof (struct TokenAttrValue));
671       val->value = val_str;
672       GNUNET_CONTAINER_DLL_insert (attr->val_head,
673                                    attr->val_tail,
674                                    val);
675       GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
676                                          &key,
677                                          attr,
678                                          GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
679     }
680
681     GNUNET_NAMESTORE_zone_iterator_next (ns_it);
682     return;
683   }
684
685   attr = GNUNET_malloc (sizeof (struct TokenAttr));
686   attr->name = GNUNET_strdup (lbl);
687   for (i = 0; i < rd_count; i++)
688   {
689     if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
690     {
691       val_str = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
692                                                   rd[i].data,
693                                                   rd[i].data_size);
694       val = GNUNET_malloc (sizeof (struct TokenAttrValue));
695       val->value = val_str;
696       GNUNET_CONTAINER_DLL_insert (attr->val_head,
697                                    attr->val_tail,
698                                    val);
699     }
700   }
701   GNUNET_CONTAINER_multihashmap_put (ego_entry->attr_map,
702                                      &key,
703                                      attr,
704                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
705   GNUNET_NAMESTORE_zone_iterator_next (ns_it);
706   return;
707 }
708
709 /**
710  *
711  * Update identity information for ego. If attribute map is
712  * dirty, first update the attributes.
713  *
714  * @param cls the ego to update
715  */
716 static void
717 update_identities(void *cls)
718 {
719   struct EgoEntry *next_ego = cls;
720   const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv_key;
721   update_task = NULL;
722   if (NULL == next_ego)
723   {
724     if (min_rel_exp.rel_value_us < MIN_WAIT_TIME.rel_value_us)
725       min_rel_exp = MIN_WAIT_TIME;
726     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
727                 ">>> Finished. Rescheduling in %lu\n",
728                 min_rel_exp.rel_value_us);
729     ns_it = NULL;
730     //finished -> reschedule
731     update_task = GNUNET_SCHEDULER_add_delayed (min_rel_exp,
732                                                 &update_identities,
733                                                 ego_head);
734     min_rel_exp.rel_value_us = 0;
735     return;
736   }
737   priv_key = GNUNET_IDENTITY_ego_get_private_key (next_ego->ego);
738   if (GNUNET_YES == next_ego->attributes_dirty)
739   {
740     //Starting over. We must update the Attributes for they might have changed.
741     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
742                                                    priv_key,
743                                                    &attribute_collect,
744                                                    next_ego);
745
746   }
747   else
748   {
749     //Ego will be dirty next time
750     next_ego->attributes_dirty = GNUNET_YES;
751     ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
752                                                    priv_key,
753                                                    &token_collect,
754                                                    next_ego);
755   }
756 }
757
758
759 /**
760  * Function called initially to start update task
761  */
762 static void
763 init_cont ()
764 {
765   GNUNET_log (GNUNET_ERROR_TYPE_INFO, ">>> Starting Service\n");
766   //Initially iterate all itenties and refresh all tokens
767   update_task = GNUNET_SCHEDULER_add_now (&update_identities,
768                                           ego_head);
769 }
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 {
870   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
871               "Shutting down...\n");
872   cleanup();
873 }
874
875
876 static struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage*
877 create_exchange_result_message (const char* token,
878                                 const char* label,
879                                 uint64_t ticket_nonce)
880 {
881   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
882   uint16_t token_len = strlen (token) + 1;
883   erm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
884                        + token_len);
885   erm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
886   erm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage)
887                             + token_len);
888   erm->ticket_nonce = htonl (ticket_nonce);
889   memcpy (&erm[1], token, token_len);
890   return erm;
891 }
892
893
894 static struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage*
895 create_issue_result_message (const char* label,
896                              const char* ticket,
897                              const char* token)
898 {
899   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
900   char *tmp_str;
901
902   irm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
903                        + strlen (label) + 1
904                        + strlen (ticket) + 1
905                        + strlen (token) + 1);
906   irm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
907   irm->header.size = htons (sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage)
908                             + strlen (label) + 1
909                             + strlen (ticket) + 1
910                             + strlen (token) + 1);
911   GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
912   memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
913   GNUNET_free (tmp_str);
914   return irm;
915 }
916
917 static void
918 cleanup_issue_handle (struct IssueHandle *handle)
919 {
920   if (NULL != handle->attr_map)
921     GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
922   if (NULL != handle->scopes)
923     GNUNET_free (handle->scopes);
924   if (NULL != handle->token)
925    token_destroy (handle->token);
926   if (NULL != handle->ticket)
927     ticket_destroy (handle->ticket);
928   if (NULL != handle->label)
929     GNUNET_free (handle->label);
930   GNUNET_free (handle);
931 }
932
933 static void
934 store_token_issue_cont (void *cls,
935                         int32_t success,
936                         const char *emsg)
937 {
938   struct IssueHandle *handle = cls;
939   struct GNUNET_IDENTITY_PROVIDER_IssueResultMessage *irm;
940   char *ticket_str;
941   char *token_str;
942   
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,
974                                      ticket_str,
975                                      token_str);
976   GNUNET_SERVER_notification_context_unicast (nc,
977                                               handle->client,
978                                               &irm->header,
979                                               GNUNET_NO);
980   GNUNET_SERVER_client_set_user_context (handle->client, NULL);
981   cleanup_issue_handle (handle);
982   GNUNET_free (irm);
983   GNUNET_free (ticket_str);
984   GNUNET_free (token_str);
985 }
986
987
988 /**
989  * Build a GNUid token for identity
990  *
991  * FIXME: doxygen is very wrong here!
992  *
993  * @param handle the handle
994  * @param ego_entry the ego to build the token for
995  * @param name name of the ego
996  * @param token_aud token audience
997  * @param token the resulting gnuid token
998  * @return identifier string of token (label)
999  */
1000 static void
1001 sign_and_return_token (void *cls)
1002 {
1003   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
1004   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
1005   struct IssueHandle *handle = cls;
1006   struct GNUNET_GNSRECORD_Data token_record[2];
1007   char *nonce_str;
1008   char *enc_token_str;
1009   char *token_metadata;
1010   char* write_ptr;
1011   uint64_t time;
1012   uint64_t exp_time;
1013   size_t token_metadata_len;
1014
1015   //Remote nonce
1016   nonce_str = NULL;
1017   GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
1018   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
1019
1020   GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
1021                                       &pub_key);
1022   handle->ticket = ticket_create (handle->nonce,
1023                                   &pub_key,
1024                                   handle->label,
1025                                   &handle->aud_key);
1026
1027   time = GNUNET_TIME_absolute_get().abs_value_us;
1028   exp_time = time + token_expiration_interval.rel_value_us;
1029
1030   token_add_attr_int (handle->token, "nbf", time);
1031   token_add_attr_int (handle->token, "iat", time);
1032   token_add_attr_int (handle->token, "exp", exp_time);
1033   token_add_attr (handle->token, "nonce", nonce_str);
1034
1035   //Token in a serialized encrypted format
1036   GNUNET_assert (token_serialize (handle->token,
1037                                   &handle->iss_key,
1038                                   &ecdhe_privkey,
1039                                   &enc_token_str));
1040
1041   //Token record E,E_K (Token)
1042   token_record[0].data = enc_token_str;
1043   token_record[0].data_size = strlen (enc_token_str) + 1;
1044   token_record[0].expiration_time = exp_time;
1045   token_record[0].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN;
1046   token_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
1047
1048
1049   token_metadata_len = sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)
1050     + sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)
1051     + strlen (handle->scopes) + 1; //With 0-Terminator
1052   token_metadata = GNUNET_malloc (token_metadata_len);
1053   write_ptr = token_metadata;
1054   memcpy (token_metadata, ecdhe_privkey, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1055   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey);
1056   memcpy (write_ptr, &handle->aud_key, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1057   write_ptr += sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1058   memcpy (write_ptr, handle->scopes, strlen (handle->scopes) + 1); //with 0-Terminator;
1059
1060   token_record[1].data = token_metadata;
1061   token_record[1].data_size = token_metadata_len;
1062   token_record[1].expiration_time = exp_time;
1063   token_record[1].record_type = GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA;
1064   token_record[1].flags = GNUNET_GNSRECORD_RF_PRIVATE;
1065
1066   //Persist token
1067   handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1068                                                   &handle->iss_key,
1069                                                   handle->label,
1070                                                   2,
1071                                                   token_record,
1072                                                   &store_token_issue_cont,
1073                                                   handle);
1074   GNUNET_free (ecdhe_privkey);
1075   GNUNET_free (nonce_str);
1076   GNUNET_free (enc_token_str);
1077   GNUNET_free (token_metadata);
1078 }
1079
1080 /**
1081  * Collect attributes for token
1082  */
1083 static void
1084 attr_collect (void *cls,
1085               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1086               const char *label,
1087               unsigned int rd_count,
1088               const struct GNUNET_GNSRECORD_Data *rd)
1089 {
1090   int i;
1091   char* data;
1092   struct IssueHandle *handle = cls;
1093   struct GNUNET_HashCode key;
1094
1095   if (NULL == label)
1096   {
1097     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
1098     handle->ns_it = NULL;
1099     GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
1100     return;
1101   }
1102
1103   GNUNET_CRYPTO_hash (label,
1104                       strlen (label),
1105                       &key);
1106
1107   if (0 == rd_count ||
1108       ( (NULL != handle->attr_map) &&
1109         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
1110                                                                &key))
1111       )
1112      )
1113   {
1114     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1115     return;
1116   }
1117
1118   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
1119
1120   if (1 == rd_count)
1121   {
1122     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1123     {
1124       data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
1125                                                rd->data,
1126                                                rd->data_size);
1127       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1128       token_add_attr (handle->token,
1129                       label,
1130                       data);
1131       GNUNET_free (data);
1132     }
1133     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1134     return;
1135   }
1136
1137   i = 0;
1138   for (; i < rd_count; i++)
1139   {
1140     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
1141     {
1142       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1143                                                rd[i].data,
1144                                                rd[i].data_size);
1145       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
1146       token_add_attr (handle->token, label, data);
1147       GNUNET_free (data);
1148     }
1149   }
1150
1151   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1152 }
1153
1154 static void
1155 cleanup_exchange_handle (struct ExchangeHandle *handle)
1156 {
1157   if (NULL != handle->ticket)
1158     ticket_destroy (handle->ticket);
1159   if (NULL != handle->token)
1160     token_destroy (handle->token);
1161   GNUNET_free (handle);
1162 }
1163
1164 static void
1165 process_lookup_result (void *cls, uint32_t rd_count,
1166                        const struct GNUNET_GNSRECORD_Data *rd)
1167 {
1168   struct ExchangeHandle *handle = cls;
1169   struct GNUNET_IDENTITY_PROVIDER_ExchangeResultMessage *erm;
1170   char* token_str;
1171   char* record_str;
1172
1173   handle->lookup_request = NULL;
1174   if (2 != rd_count)
1175   {
1176     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1177                 "Number of tokens %d != 2.",
1178                 rd_count);
1179     cleanup_exchange_handle (handle);
1180     GNUNET_SCHEDULER_add_now (&do_shutdown, handle);
1181     return;
1182   }
1183
1184   record_str =
1185     GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1186                                       rd->data,
1187                                       rd->data_size);
1188
1189   //Decrypt and parse
1190   GNUNET_assert (GNUNET_OK ==  token_parse (record_str,
1191                                             &handle->aud_privkey,
1192                                             &handle->token));
1193
1194   //Readable
1195   GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
1196                                                &handle->aud_privkey,
1197                                                &token_str));
1198
1199   erm = create_exchange_result_message (token_str,
1200                                         handle->label,
1201                                         handle->ticket->payload->nonce);
1202   GNUNET_SERVER_notification_context_unicast (nc,
1203                                               handle->client,
1204                                               &erm->header,
1205                                               GNUNET_NO);
1206   GNUNET_SERVER_client_set_user_context (handle->client, NULL);
1207
1208   cleanup_exchange_handle (handle);
1209   GNUNET_free (record_str);
1210   GNUNET_free (token_str);
1211   GNUNET_free (erm);
1212
1213 }
1214
1215
1216
1217 /**
1218  *
1219  * Handler for exchange message
1220  *
1221  * @param cls unused
1222  * @param client who sent the message
1223  * @param message the message
1224  */
1225 static void
1226 handle_exchange_message (void *cls,
1227                          struct GNUNET_SERVER_Client *client,
1228                          const struct GNUNET_MessageHeader *message)
1229 {
1230   const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *em;
1231   struct ExchangeHandle *xchange_handle;
1232   uint16_t size;
1233   const char *ticket;
1234   char *lookup_query;
1235
1236   size = ntohs (message->size);
1237   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage))
1238   {
1239     GNUNET_break (0);
1240     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1241     return;
1242   }
1243   em = (const struct GNUNET_IDENTITY_PROVIDER_ExchangeMessage *) message;
1244   ticket = (const char *) &em[1];
1245   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1246               "Received EXCHANGE of `%s' from client\n",
1247               ticket);
1248   xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1249   xchange_handle->aud_privkey = em->aud_privkey;
1250
1251   if (GNUNET_SYSERR == ticket_parse (ticket,
1252                                      &xchange_handle->aud_privkey,
1253                                      &xchange_handle->ticket))
1254   {
1255     GNUNET_free (xchange_handle);
1256     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1257     return;
1258   }
1259   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for token under %s\n",
1260               xchange_handle->ticket->payload->label);
1261   GNUNET_asprintf (&lookup_query,
1262                    "%s.gnu",
1263                    xchange_handle->ticket->payload->label);
1264   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1265   GNUNET_SERVER_notification_context_add (nc, client);
1266   GNUNET_SERVER_client_set_user_context (client, xchange_handle);
1267   xchange_handle->client = client;
1268   xchange_handle->lookup_request = GNUNET_GNS_lookup (gns_handle,
1269                                                       lookup_query,
1270                                                       &xchange_handle->ticket->payload->identity_key,
1271                                                       GNUNET_GNSRECORD_TYPE_ID_TOKEN,
1272                                                       GNUNET_GNS_LO_LOCAL_MASTER,
1273                                                       NULL,
1274                                                       &process_lookup_result,
1275                                                       xchange_handle);
1276   GNUNET_free (lookup_query);
1277
1278 }
1279
1280
1281 /**
1282  *
1283  * Look for existing token
1284  *
1285  * @param cls the identity entry
1286  * @param zone the identity
1287  * @param lbl the name of the record
1288  * @param rd_count number of records
1289  * @param rd record data
1290  *
1291  */
1292 static void
1293 find_existing_token (void *cls,
1294                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1295                      const char *lbl,
1296                      unsigned int rd_count,
1297                      const struct GNUNET_GNSRECORD_Data *rd)
1298 {
1299   struct IssueHandle *handle = cls;
1300   const struct GNUNET_GNSRECORD_Data *token_metadata_record;
1301   struct GNUNET_CRYPTO_EcdsaPublicKey *aud_key;
1302   struct GNUNET_HashCode key;
1303   int scope_count_token;
1304   uint64_t rnd_key;
1305   char *scope;
1306   char *tmp_scopes;
1307
1308   if (NULL == lbl)
1309   {
1310     //Done
1311     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1312                 ">>> No existing token found\n");
1313     //Label
1314     rnd_key =
1315       GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1316                                 UINT64_MAX);
1317     GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1318                                   sizeof (uint64_t),
1319                                   &handle->label);
1320     handle->ns_it = NULL;
1321     handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1322                                                            &handle->iss_key,
1323                                                            &attr_collect,
1324                                                            handle);
1325     return;
1326   }
1327
1328   //There should be only a single record for a token under a label
1329   if (2 != rd_count)
1330   {
1331     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1332     return;
1333   }
1334
1335   if (rd[0].record_type == GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1336   {
1337     token_metadata_record = &rd[0];
1338   } else {
1339     token_metadata_record = &rd[1];
1340   }
1341   if (token_metadata_record->record_type != GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA)
1342   {
1343     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1344     return;
1345   }
1346   ecdhe_privkey = *((struct GNUNET_CRYPTO_EcdhePrivateKey *)token_metadata_record->data);
1347   aud_key =
1348     (struct GNUNET_CRYPTO_EcdsaPublicKey *)(token_metadata_record->data+sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
1349   tmp_scopes = GNUNET_strdup ((char*) aud_key+sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1350
1351   if (0 != memcmp (aud_key, &handle->aud_key,
1352                    sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1353   {
1354     char *tmp2 = GNUNET_STRINGS_data_to_string_alloc (aud_key,
1355                                                       sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
1356     //Audience does not match!
1357     char *tmp = GNUNET_GNSRECORD_value_to_string (GNUNET_GNSRECORD_TYPE_ID_TOKEN_METADATA,
1358                                                   token_metadata_record->data,
1359                                                   token_metadata_record->data_size);
1360     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1361                 "Token does not match audience %s vs %s. Moving on\n",
1362                 tmp2,
1363                 tmp);
1364     GNUNET_free (tmp_scopes);
1365     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1366     return;
1367   }
1368
1369   scope = strtok (tmp_scopes, ",");
1370   scope_count_token = 0;
1371   while (NULL != scope)
1372   {
1373     GNUNET_CRYPTO_hash (scope,
1374                         strlen (scope),
1375                         &key);
1376
1377     if ((NULL != handle->attr_map) &&
1378         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map, &key)))
1379     {
1380       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1381                   "Issued token does not include `%s'. Moving on\n", scope);
1382       GNUNET_free (tmp_scopes);
1383       GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1384       return;
1385     }
1386     scope_count_token++;
1387     scope = strtok (NULL, ",");
1388   }
1389   GNUNET_free (tmp_scopes);
1390   //All scopes in token are also in request. Now
1391   //Check length
1392   if (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) == scope_count_token)
1393   {
1394     //We have an existing token
1395     handle->label = GNUNET_strdup (lbl);
1396     handle->ns_it = NULL;
1397     handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1398                                                            &handle->iss_key,
1399                                                            &attr_collect,
1400                                                            handle);
1401
1402     return;
1403   }
1404   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1405               "Nuber of attributes in token do not match request\n");
1406   //No luck
1407   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
1408 }
1409
1410
1411 /**
1412  *
1413  * Handler for issue message
1414  *
1415  * @param cls unused
1416  * @param client who sent the message
1417  * @param message the message
1418  */
1419 static void
1420 handle_issue_message (void *cls,
1421                       struct GNUNET_SERVER_Client *client,
1422                       const struct GNUNET_MessageHeader *message)
1423 {
1424   const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *im;
1425   const char *scopes;
1426
1427   uint16_t size;
1428   char *scopes_tmp;
1429   char *scope;
1430   struct GNUNET_HashCode key;
1431   struct IssueHandle *issue_handle;
1432
1433   size = ntohs (message->size);
1434   if (size <= sizeof (struct GNUNET_IDENTITY_PROVIDER_IssueMessage))
1435   {
1436     GNUNET_break (0);
1437     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1438     return;
1439   }
1440   im = (const struct GNUNET_IDENTITY_PROVIDER_IssueMessage *) message;
1441   scopes = (const char *) &im[1];
1442   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1443   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1444                                                                  GNUNET_NO);
1445   /* FIXME: check that scopes is 0-termianted, Out-of-bounds access
1446      possible here!!! */
1447   scopes_tmp = GNUNET_strdup (scopes);
1448   scope = strtok(scopes_tmp, ",");
1449   for (; NULL != scope; scope = strtok (NULL, ","))
1450   {
1451     GNUNET_CRYPTO_hash (scope,
1452                         strlen (scope),
1453                         &key);
1454     GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1455                                        &key,
1456                                        scope,
1457                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1458   }
1459   GNUNET_free (scopes_tmp);
1460
1461   issue_handle->aud_key = im->aud_key;
1462   issue_handle->iss_key = im->iss_key;
1463   GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1464                                       &issue_handle->iss_pkey);
1465   issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1466   issue_handle->nonce = ntohl (im->nonce);
1467   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1468   GNUNET_SERVER_notification_context_add (nc, client);
1469   GNUNET_SERVER_client_set_user_context (client, issue_handle);
1470   issue_handle->client = client;
1471   issue_handle->scopes = GNUNET_strdup (scopes);
1472   issue_handle->token = token_create (&issue_handle->iss_pkey,
1473                                       &issue_handle->aud_key);
1474
1475   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1476                                                                &im->iss_key,
1477                                                                &find_existing_token,
1478                                                                issue_handle);
1479 }
1480
1481 /**
1482  * Main function that will be run
1483  *
1484  * @param cls closure
1485  * @param args remaining command-line arguments
1486  * @param cfgfile name of the configuration file used (for saving, can be NULL)
1487  * @param c configuration
1488  */
1489 static void
1490 run (void *cls,
1491      struct GNUNET_SERVER_Handle *server,
1492      const struct GNUNET_CONFIGURATION_Handle *c)
1493 {
1494   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1495     {&handle_issue_message, NULL,
1496       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE, 0},
1497     {&handle_exchange_message, NULL,
1498       GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE, 0},
1499     {NULL, NULL, 0, 0}
1500   };
1501
1502   cfg = c;
1503
1504   stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1505   GNUNET_SERVER_add_handlers (server, handlers);
1506   nc = GNUNET_SERVER_notification_context_create (server, 1);
1507
1508   //Connect to identity and namestore services
1509   ns_handle = GNUNET_NAMESTORE_connect (cfg);
1510   if (NULL == ns_handle)
1511   {
1512     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1513   }
1514
1515   gns_handle = GNUNET_GNS_connect (cfg);
1516   if (NULL == gns_handle)
1517   {
1518     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1519   }
1520
1521   identity_handle = GNUNET_IDENTITY_connect (cfg,
1522                                              &list_ego,
1523                                              NULL);
1524
1525   if (GNUNET_OK ==
1526       GNUNET_CONFIGURATION_get_value_time (cfg,
1527                                            "identity-provider",
1528                                            "TOKEN_EXPIRATION_INTERVAL",
1529                                            &token_expiration_interval))
1530   {
1531     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1532                 "Time window for zone iteration: %s\n",
1533                 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1534                                                         GNUNET_YES));
1535   } else {
1536     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1537   }
1538
1539   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1540 }
1541
1542
1543 /**
1544  * The main function
1545  *
1546  * @param argc number of arguments from the cli
1547  * @param argv command line arguments
1548  * @return 0 ok, 1 on error
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-service-identity-provider.c */