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