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