-fixes
[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_credential_service.h"
34 #include "gnunet_statistics_service.h"
35 #include "gnunet_gns_service.h"
36 #include "gnunet_signatures.h"
37 #include "identity_provider.h"
38 #include "identity_token.h"
39 #include <inttypes.h>
40
41 /**
42  * First pass state
43  */
44 #define STATE_INIT 0
45
46 /**
47  * Normal operation state
48  */
49 #define STATE_POST_INIT 1
50
51 /**
52  * Minimum interval between updates
53  */
54 #define MIN_WAIT_TIME GNUNET_TIME_UNIT_MINUTES
55
56 /**
57  * Standard token expiration time
58  */
59 #define DEFAULT_TOKEN_EXPIRATION_INTERVAL GNUNET_TIME_UNIT_HOURS
60
61 /**
62  * Identity handle
63  */
64 static struct GNUNET_IDENTITY_Handle *identity_handle;
65
66 /**
67  * Token expiration interval
68  */
69 static struct GNUNET_TIME_Relative token_expiration_interval;
70
71 /**
72  * Namestore handle
73  */
74 static struct GNUNET_NAMESTORE_Handle *ns_handle;
75
76 /**
77  * GNS handle
78  */
79 static struct GNUNET_GNS_Handle *gns_handle;
80
81 /**
82  * Credential handle
83  */
84 static struct GNUNET_CREDENTIAL_Handle *credential_handle;
85
86 /**
87  * Namestore qe
88  */
89 static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
90
91 /**
92  * Namestore iterator
93  */
94 static struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
95
96 /**
97  * Timeout task
98  */
99 static struct GNUNET_SCHEDULER_Task *timeout_task;
100
101 /**
102  * Update task
103  */
104 static struct GNUNET_SCHEDULER_Task *update_task;
105
106
107 /**
108  * Currently processed token
109  */
110 static struct IdentityToken *token;
111
112 /**
113  * Label for currently processed token
114  */
115 static char* label;
116
117 /**
118  * Scopes for processed token
119  */
120 static char* scopes;
121
122 /**
123  * Handle to the statistics service.
124  */
125 static struct GNUNET_STATISTICS_Handle *stats;
126
127 /**
128  * Our configuration.
129  */
130 static const struct GNUNET_CONFIGURATION_Handle *cfg;
131
132 struct VerifiedAttributeEntry
133 {
134   /**
135    * DLL
136    */
137   struct VerifiedAttributeEntry *prev;
138
139   /**
140    * DLL
141    */
142   struct VerifiedAttributeEntry *next;
143
144   /**
145    * Attribute Name
146    */
147   char* name;
148 };
149
150 struct ParallelLookups;
151
152 struct ExchangeHandle
153 {
154
155   /**
156    * Client connection
157    */
158   struct GNUNET_SERVICE_Client *client;
159
160   /**
161    * Ticket
162    */
163   struct TokenTicket *ticket;
164
165   /**
166    * Token returned
167    */
168   struct IdentityToken *token;
169
170   /**
171    * LookupRequest
172    */
173   struct GNUNET_GNS_LookupRequest *lookup_request;
174
175   /**
176    * Audience Key
177    */
178   struct GNUNET_CRYPTO_EcdsaPrivateKey aud_privkey;
179   
180   /**
181    * ParallelLookups DLL
182    */
183   struct ParallelLookup *parallel_lookups_head;
184   struct ParallelLookup *parallel_lookups_tail;
185   
186   struct GNUNET_SCHEDULER_Task *kill_task;
187   struct GNUNET_CRYPTO_AbeKey *key;
188
189   /**
190    * Label to return
191    */
192   char *label;
193
194   /**
195    * request id
196    */
197   uint32_t r_id;
198 };
199
200 struct ParallelLookup
201 {
202   struct ParallelLookup *next;
203
204   struct ParallelLookup *prev;
205
206   struct GNUNET_GNS_LookupRequest *lookup_request;
207
208   struct ExchangeHandle *handle;
209
210   char *label;
211 };
212
213 struct IssueHandle
214 {
215
216   /**
217    * Client connection
218    */
219   struct GNUNET_SERVICE_Client *client;
220
221   /**
222    * Issuer Key
223    */
224   struct GNUNET_CRYPTO_EcdsaPrivateKey iss_key;
225
226   /**
227    * Issue pubkey
228    */
229   struct GNUNET_CRYPTO_EcdsaPublicKey iss_pkey;
230
231   /**
232    * Audience Key
233    */
234   struct GNUNET_CRYPTO_EcdsaPublicKey aud_key;
235
236   /**
237    * The issuer egos ABE master key
238    */
239   struct GNUNET_CRYPTO_AbeMasterKey *abe_key;
240
241   /**
242    * Expiration
243    */
244   struct GNUNET_TIME_Absolute expiration;
245
246   /**
247    * Scopes
248    */
249   char *scopes;
250
251   /**
252    * DLL
253    */
254   struct VerifiedAttributeEntry *v_attr_head;
255
256   /**
257    * DLL
258    */
259   struct VerifiedAttributeEntry *v_attr_tail;
260
261   /**
262    * nonce
263    */
264   uint64_t nonce;
265
266   /**
267    * NS iterator
268    */
269   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
270
271   /**
272    * Cred request
273    */
274   struct GNUNET_CREDENTIAL_Request *credential_request;
275
276   /**
277    * Attribute map
278    */
279   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
280
281   /**
282    * Token
283    */
284   struct IdentityToken *token;
285
286   /**
287    * Ticket
288    */
289   struct TokenTicket *ticket;
290
291   /**
292    * QueueEntry
293    */
294   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
295
296   /**
297    * The label the token is stored under
298    */
299   char *label;
300
301   /**
302    * request id
303    */
304   uint32_t r_id;
305 };
306
307 /**
308  * DLL for ego handles to egos containing the ID_ATTRS in a map in json_t format
309  *
310  */
311 struct EgoEntry
312 {
313   /**
314    * DLL
315    */
316   struct EgoEntry *next;
317
318   /**
319    * DLL
320    */
321   struct EgoEntry *prev;
322
323   /**
324    * Ego handle
325    */
326   struct GNUNET_IDENTITY_Ego *ego;
327
328   /**
329    * Attribute map. Contains the attributes as json_t
330    */
331   struct GNUNET_CONTAINER_MultiHashMap *attr_map;
332
333 };
334
335 /**
336  * Cleanup task
337  */
338 static void
339 cleanup()
340 {
341   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
342               "Cleaning up\n");
343   if (NULL != stats)
344   {
345     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
346     stats = NULL;
347   }
348
349   if (NULL != timeout_task)
350     GNUNET_SCHEDULER_cancel (timeout_task);
351   if (NULL != update_task)
352     GNUNET_SCHEDULER_cancel (update_task);
353   if (NULL != identity_handle)
354     GNUNET_IDENTITY_disconnect (identity_handle);
355   if (NULL != gns_handle)
356     GNUNET_GNS_disconnect (gns_handle);
357   if (NULL != credential_handle)
358     GNUNET_CREDENTIAL_disconnect (credential_handle);
359   if (NULL != ns_it)
360     GNUNET_NAMESTORE_zone_iteration_stop (ns_it);
361   if (NULL != ns_qe)
362     GNUNET_NAMESTORE_cancel (ns_qe);
363   if (NULL != ns_handle)
364     GNUNET_NAMESTORE_disconnect (ns_handle);
365   if (NULL != token)
366     GNUNET_free (token);
367   if (NULL != label)
368     GNUNET_free (label);
369
370 }
371
372 /**
373  * Shutdown task
374  *
375  * @param cls NULL
376  * @param tc task context
377  */
378 static void
379 do_shutdown (void *cls)
380 {
381   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
382               "Shutting down...\n");
383   cleanup();
384 }
385
386
387 static struct GNUNET_MQ_Envelope*
388 create_exchange_result_message (const char* token,
389                                 const char* label,
390                                 uint64_t ticket_nonce,
391                                 uint64_t id)
392 {
393   struct GNUNET_MQ_Envelope *env;
394   struct ExchangeResultMessage *erm;
395   uint16_t token_len = strlen (token) + 1;
396
397   env = GNUNET_MQ_msg_extra (erm,
398                              token_len,
399                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE_RESULT);
400   erm->ticket_nonce = htonl (ticket_nonce);
401   erm->id = id;
402   GNUNET_memcpy (&erm[1], token, token_len);
403   return env;
404 }
405
406
407 static struct GNUNET_MQ_Envelope*
408 create_issue_result_message (const char* label,
409                              const char* ticket,
410                              const char* token,
411                              uint64_t id)
412 {
413   struct GNUNET_MQ_Envelope *env;
414   struct IssueResultMessage *irm;
415   char *tmp_str;
416   size_t len;
417
418   GNUNET_asprintf (&tmp_str, "%s,%s,%s", label, ticket, token);
419   len = strlen (tmp_str) + 1;
420   env = GNUNET_MQ_msg_extra (irm,
421                              len,
422                              GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE_RESULT);
423   irm->id = id;
424   GNUNET_memcpy (&irm[1], tmp_str, strlen (tmp_str) + 1);
425   GNUNET_free (tmp_str);
426   return env;
427 }
428
429 static void
430 cleanup_issue_handle (struct IssueHandle *handle)
431 {
432   if (NULL != handle->attr_map)
433     GNUNET_CONTAINER_multihashmap_destroy (handle->attr_map);
434   if (NULL != handle->scopes)
435     GNUNET_free (handle->scopes);
436   if (NULL != handle->token)
437     token_destroy (handle->token);
438   if (NULL != handle->ticket)
439     ticket_destroy (handle->ticket);
440   if (NULL != handle->label)
441     GNUNET_free (handle->label);
442   if (NULL != handle->ns_it)
443     GNUNET_NAMESTORE_zone_iteration_stop (handle->ns_it);
444   if (NULL != handle->credential_request)
445     GNUNET_CREDENTIAL_request_cancel (handle->credential_request);
446   GNUNET_free (handle);
447 }
448
449 static void
450 store_record_issue_cont (void *cls,
451                         int32_t success,
452                         const char *emsg)
453 {
454   struct IssueHandle *handle = cls;
455   struct GNUNET_MQ_Envelope *env;
456   char *ticket_str;
457   char *token_str;
458
459   handle->ns_qe = NULL;
460   if (GNUNET_SYSERR == success)
461   {
462     cleanup_issue_handle (handle);
463     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
464                 "Unknown Error\n");
465     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
466     return;
467   }
468   if (GNUNET_OK != ticket_serialize (handle->ticket,
469                                      &handle->iss_key,
470                                      &ticket_str))
471   {
472     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
473                 "Error serializing ticket\n");
474     cleanup_issue_handle (handle);
475     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
476     return;
477   }
478   if (GNUNET_OK != token_to_string (handle->token,
479                                     &handle->iss_key,
480                                     &token_str))
481   {
482     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n",
483                 "Error serializing token\n");
484     GNUNET_free (ticket_str);
485     cleanup_issue_handle (handle);
486     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
487     return;
488   }
489   env = create_issue_result_message (handle->label,
490                                      ticket_str,
491                                      token_str,
492                                      handle->r_id);
493   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
494                   env);
495   cleanup_issue_handle (handle);
496   GNUNET_free (ticket_str);
497   GNUNET_free (token_str);
498 }
499
500 static int
501 create_sym_key_from_ecdh(const struct GNUNET_HashCode *new_key_hash,
502                          struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
503                          struct GNUNET_CRYPTO_SymmetricInitializationVector *iv)
504 {
505   struct GNUNET_CRYPTO_HashAsciiEncoded new_key_hash_str;
506
507   GNUNET_CRYPTO_hash_to_enc (new_key_hash,
508                              &new_key_hash_str);
509   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating symmetric rsa key from %s\n", (char*)&new_key_hash_str);
510   static const char ctx_key[] = "gnuid-aes-ctx-key";
511   GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
512                      new_key_hash, sizeof (struct GNUNET_HashCode),
513                      ctx_key, strlen (ctx_key),
514                      NULL, 0);
515   static const char ctx_iv[] = "gnuid-aes-ctx-iv";
516   GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
517                      new_key_hash, sizeof (struct GNUNET_HashCode),
518                      ctx_iv, strlen (ctx_iv),
519                      NULL, 0);
520   return GNUNET_OK;
521 }
522
523 int
524 serialize_abe_keyinfo (const struct IssueHandle *handle,
525                  const struct GNUNET_CRYPTO_AbeKey *rp_key,
526                  struct GNUNET_CRYPTO_EcdhePrivateKey **ecdh_privkey,
527                  char **result)
528 {
529   char *enc_keyinfo;
530   char *serialized_key;
531   char *buf;
532   struct GNUNET_CRYPTO_EcdhePublicKey ecdh_pubkey;
533   ssize_t size;
534   
535   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
536   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
537   struct GNUNET_HashCode new_key_hash;
538   ssize_t enc_size;
539   
540   size = GNUNET_CRYPTO_cpabe_serialize_key (rp_key,
541                                             (void**)&serialized_key);
542   buf = GNUNET_malloc (strlen (handle->scopes) + 1 + size);
543   GNUNET_memcpy (buf,
544                  handle->scopes,
545                  strlen (handle->scopes) + 1);
546   GNUNET_memcpy (buf + strlen (handle->scopes) + 1,
547                  serialized_key,
548                  size);
549   // ECDH keypair E = eG
550   *ecdh_privkey = GNUNET_CRYPTO_ecdhe_key_create();
551   GNUNET_CRYPTO_ecdhe_key_get_public (*ecdh_privkey,
552                                       &ecdh_pubkey);
553   enc_keyinfo = GNUNET_malloc (size + strlen (handle->scopes) + 1);
554   // Derived key K = H(eB)
555   GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdh_ecdsa (*ecdh_privkey,
556                                                         &handle->aud_key,
557                                                         &new_key_hash));
558   create_sym_key_from_ecdh(&new_key_hash, &skey, &iv);
559   enc_size = GNUNET_CRYPTO_symmetric_encrypt (buf,
560                                               size + strlen (handle->scopes) + 1,
561                                               &skey, &iv,
562                                               enc_keyinfo);
563   *result = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+
564                            enc_size);
565   GNUNET_memcpy (*result,
566                  &ecdh_pubkey,
567                  sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
568   GNUNET_memcpy (*result + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
569                  enc_keyinfo,
570                  enc_size);
571   GNUNET_free (enc_keyinfo);
572   return sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)+enc_size;
573 }
574
575 static void
576 cleanup_exchange_handle (struct ExchangeHandle *handle)
577 {
578   if (NULL != handle->ticket)
579     ticket_destroy (handle->ticket);
580   if (NULL != handle->token)
581     token_destroy (handle->token);
582   GNUNET_free (handle);
583 }
584
585
586 /**
587  * Build a token and store it
588  *
589  * @param cls the IssueHandle
590  */
591 static void
592 sign_and_return_token (void *cls)
593 {
594   struct ExchangeHandle *handle = cls;
595   struct GNUNET_MQ_Envelope *env;
596   char *token_str;
597   uint64_t time;
598   uint64_t exp_time;
599
600   time = GNUNET_TIME_absolute_get().abs_value_us;
601   exp_time = time + token_expiration_interval.rel_value_us;
602
603   token_add_attr_int (handle->token, "nbf", time);
604   token_add_attr_int (handle->token, "iat", time);
605   token_add_attr_int (handle->token, "exp", exp_time);
606   
607   //Readable
608   GNUNET_assert (GNUNET_OK == token_to_string (handle->token,
609                                                &handle->aud_privkey,
610                                                &token_str));
611
612   env = create_exchange_result_message (token_str,
613                                         handle->label,
614                                         handle->ticket->payload->nonce,
615                                         handle->r_id);
616   GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(handle->client),
617                   env);
618   cleanup_exchange_handle (handle);
619   GNUNET_free (token_str);
620
621 }
622
623 /**
624  * Build an ABE key and store it
625  *
626  * @param cls the IssueHandle
627  */
628 static void
629 issue_ticket (void *cls)
630 {
631   struct GNUNET_CRYPTO_EcdsaPublicKey pub_key;
632   struct GNUNET_CRYPTO_EcdhePrivateKey *ecdhe_privkey;
633   struct IssueHandle *handle = cls;
634   struct GNUNET_GNSRECORD_Data code_record[1];
635   struct GNUNET_CRYPTO_AbeKey *rp_key;
636   char *nonce_str;
637   char *code_record_data;
638   char **attrs;
639   char *scope;
640   char *scopes_tmp;
641   int attrs_len;
642   int i;
643   uint64_t time;
644   uint64_t exp_time;
645   size_t code_record_len;
646
647   //Remote nonce
648   nonce_str = NULL;
649   GNUNET_asprintf (&nonce_str, "%lu", handle->nonce);
650   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Request nonce: %s\n", nonce_str);
651
652   GNUNET_CRYPTO_ecdsa_key_get_public (&handle->iss_key,
653                                       &pub_key);
654   handle->ticket = ticket_create (handle->nonce,
655                                   &pub_key,
656                                   handle->label,
657                                   &handle->aud_key);
658
659   time = GNUNET_TIME_absolute_get().abs_value_us;
660   exp_time = time + token_expiration_interval.rel_value_us;
661
662   token_add_attr_int (handle->token, "nbf", time);
663   token_add_attr_int (handle->token, "iat", time);
664   token_add_attr_int (handle->token, "exp", exp_time);
665   token_add_attr (handle->token, "nonce", nonce_str);
666
667   //Create new ABE key for RP
668   attrs_len = (GNUNET_CONTAINER_multihashmap_size (handle->attr_map) + 1) * sizeof (char*);
669   attrs = GNUNET_malloc (attrs_len);
670   i = 0;
671   scopes_tmp = GNUNET_strdup (handle->scopes);
672   for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ",")) {
673     attrs[i] = scope;
674     i++;
675   }
676   rp_key = GNUNET_CRYPTO_cpabe_create_key (handle->abe_key,
677                                            attrs);
678   code_record_len = serialize_abe_keyinfo (handle,
679                                            rp_key,
680                                            &ecdhe_privkey,
681                                            &code_record_data);
682   code_record[0].data = code_record_data;
683   code_record[0].data_size = code_record_len;
684   code_record[0].expiration_time = exp_time;
685   code_record[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_KEY;
686   code_record[0].flags = GNUNET_GNSRECORD_RF_NONE;
687
688
689   //Publish record
690   handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
691                                                   &handle->iss_key,
692                                                   handle->label,
693                                                   1,
694                                                   code_record,
695                                                   &store_record_issue_cont,
696                                                   handle);
697   GNUNET_free (ecdhe_privkey);
698   GNUNET_free (nonce_str);
699   GNUNET_free (code_record_data);
700 }
701
702 /**
703  * Credential to JSON
704  * @param cred the credential
705  * @return the resulting json, NULL if failed
706  */
707 static json_t*
708 credential_to_json (struct GNUNET_CREDENTIAL_Credential *cred)
709 {
710   char *issuer;
711   char *subject;
712   char *signature;
713   char attribute[cred->issuer_attribute_len + 1];
714   json_t *cred_obj;
715
716   issuer = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->issuer_key);
717   if (NULL == issuer)
718   {
719     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720                 "Issuer in credential malformed\n");
721     return NULL;
722   }  
723   subject = GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
724   if (NULL == subject)
725   {
726     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
727                 "Subject in credential malformed\n");
728     GNUNET_free (issuer);
729     return NULL;
730   }
731   GNUNET_STRINGS_base64_encode ((char*)&cred->signature,
732                                 sizeof (struct GNUNET_CRYPTO_EcdsaSignature),
733                                 &signature);
734   memcpy (attribute,
735           cred->issuer_attribute,
736           cred->issuer_attribute_len);
737   attribute[cred->issuer_attribute_len] = '\0';
738   cred_obj = json_object ();
739   json_object_set_new (cred_obj, "issuer", json_string (issuer));
740   json_object_set_new (cred_obj, "subject", json_string (subject));
741   json_object_set_new (cred_obj, "attribute", json_string (attribute));
742   json_object_set_new (cred_obj, "signature", json_string (signature));
743   json_object_set_new (cred_obj, "expiration", json_integer (cred->expiration.abs_value_us));
744   GNUNET_free (issuer);
745   GNUNET_free (subject);
746   GNUNET_free (signature);
747   return cred_obj;
748 }
749
750
751 static void
752 handle_vattr_collection (void* cls,
753                          unsigned int d_count,
754                          struct GNUNET_CREDENTIAL_Delegation *dc,
755                          unsigned int c_count,
756                          struct GNUNET_CREDENTIAL_Credential *cred)
757 {
758   struct IssueHandle *handle = cls;
759   struct VerifiedAttributeEntry *vattr;
760   json_t *cred_json;
761   json_t *cred_array;
762   int i;
763   handle->credential_request = NULL;
764
765   if (NULL == cred)
766   {
767     GNUNET_SCHEDULER_add_now (&issue_ticket, handle);
768     return;
769   }
770   cred_array = json_array();
771   for (i=0;i<c_count;i++)
772   {
773     cred_json = credential_to_json (cred);
774     if (NULL == cred_json)
775       continue;
776     json_array_append (cred_array, cred_json);
777     token_add_attr_json (handle->token,
778                          handle->v_attr_head->name,
779                          cred_array);
780   }
781   json_decref (cred_array);
782   vattr = handle->v_attr_head;
783
784   GNUNET_CONTAINER_DLL_remove (handle->v_attr_head,
785                                handle->v_attr_tail,
786                                vattr);
787   GNUNET_free (vattr->name);
788   GNUNET_free (vattr);
789
790   if (NULL == handle->v_attr_head)
791   {
792     GNUNET_SCHEDULER_add_now (&issue_ticket, handle);
793     return;
794   }
795   handle->credential_request = GNUNET_CREDENTIAL_collect (credential_handle,
796                                                           &handle->aud_key,
797                                                           handle->v_attr_head->name,
798                                                           &handle->iss_key,
799                                                           &handle_vattr_collection,
800                                                           handle);
801
802 }
803
804
805 static void
806 attr_collect_error (void *cls)
807 {
808   struct IssueHandle *handle = cls;
809
810   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Adding attribute Error!\n");
811   handle->ns_it = NULL;
812   GNUNET_SCHEDULER_add_now (&issue_ticket, handle);
813 }
814
815
816 static void
817 attr_collect_finished (void *cls)
818 {
819   struct IssueHandle *handle = cls;
820
821   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute END: \n");
822   handle->ns_it = NULL;
823
824   if (NULL == handle->v_attr_head)
825   {
826     GNUNET_SCHEDULER_add_now (&issue_ticket, handle);
827     return;
828   }
829   handle->credential_request = GNUNET_CREDENTIAL_collect (credential_handle,
830                                                           &handle->aud_key,
831                                                           handle->v_attr_head->name,
832                                                           &handle->iss_key,
833                                                           &handle_vattr_collection,
834                                                           handle);
835 }
836 /**
837  * Collect attributes for token
838  */
839 static void
840 attr_collect (void *cls,
841               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
842               const char *label,
843               unsigned int rd_count,
844               const struct GNUNET_GNSRECORD_Data *rd)
845 {
846   struct IssueHandle *handle = cls;
847   int i;
848   char* data;
849   struct GNUNET_HashCode key;
850
851   GNUNET_CRYPTO_hash (label,
852                       strlen (label),
853                       &key);
854
855   if (0 == rd_count ||
856       ( (NULL != handle->attr_map) &&
857         (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains (handle->attr_map,
858                                                                &key))
859       )
860      )
861   {
862     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
863     return;
864   }
865
866   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute: %s\n", label);
867
868   if (1 == rd_count)
869   {
870     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
871     {
872       data = GNUNET_GNSRECORD_value_to_string (rd->record_type,
873                                                rd->data,
874                                                rd->data_size);
875       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
876       token_add_attr (handle->token,
877                       label,
878                       data);
879       GNUNET_free (data);
880     }
881     GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
882     return;
883   }
884
885   i = 0;
886   for (; i < rd_count; i++)
887   {
888     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
889     {
890       data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
891                                                rd[i].data,
892                                                rd[i].data_size);
893       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding value: %s\n", data);
894       token_add_attr (handle->token, label, data);
895       GNUNET_free (data);
896     }
897   }
898
899   GNUNET_NAMESTORE_zone_iterator_next (handle->ns_it);
900 }
901
902 static void
903 process_parallel_lookup (void *cls, uint32_t rd_count,
904                          const struct GNUNET_GNSRECORD_Data *rd)
905 {
906   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
907               "Parallel lookup finished (count=%u)\n", rd_count);
908   struct ParallelLookup *parallel_lookup = cls;
909   struct ExchangeHandle *handle = parallel_lookup->handle;
910   char *data;
911   int i;
912
913   GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
914                                handle->parallel_lookups_tail,
915                                parallel_lookup);
916   GNUNET_free (parallel_lookup);
917   if (1 == rd_count)
918   {
919     if (rd->record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
920     {
921       GNUNET_CRYPTO_cpabe_decrypt (rd->data,
922                                    rd->data_size,
923                                    handle->key,
924                                    (void**)&data);
925       GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Adding value: %s\n", data);
926       token_add_attr (handle->token,
927                       parallel_lookup->label,
928                       data);
929       GNUNET_free (data);
930     }
931   } else {
932     i = 0;
933     for (; i < rd_count; i++)
934     {
935       if (rd[i].record_type == GNUNET_GNSRECORD_TYPE_ID_ATTR)
936       {
937         data = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
938                                                  rd[i].data,
939                                                  rd[i].data_size);
940         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Adding value: %s\n", data);
941         token_add_attr (handle->token, parallel_lookup->label, data);
942         GNUNET_free (data);
943       }
944     }
945   }
946   if (NULL != handle->parallel_lookups_head)
947     return; //Wait for more
948   //Else we are done
949   GNUNET_SCHEDULER_cancel (handle->kill_task);
950   GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
951 }
952
953 void
954 abort_parallel_lookups (void *cls)
955 {
956   struct ExchangeHandle *handle = cls;
957   struct ParallelLookup *lu;
958   struct ParallelLookup *tmp;
959
960   for (lu = handle->parallel_lookups_head;
961        NULL != lu;) {
962     GNUNET_GNS_lookup_cancel (lu->lookup_request);
963     GNUNET_free (lu->label);
964     tmp = lu->next;
965     GNUNET_CONTAINER_DLL_remove (handle->parallel_lookups_head,
966                                  handle->parallel_lookups_tail,
967                                  lu);
968       GNUNET_free (lu);
969       lu = tmp;
970   }
971   GNUNET_SCHEDULER_add_now (&sign_and_return_token, handle);
972
973 }
974
975 static void
976 process_lookup_result (void *cls, uint32_t rd_count,
977                        const struct GNUNET_GNSRECORD_Data *rd)
978 {
979   struct ExchangeHandle *handle = cls;
980   struct GNUNET_HashCode new_key_hash;
981   struct GNUNET_CRYPTO_SymmetricSessionKey enc_key;
982   struct GNUNET_CRYPTO_SymmetricInitializationVector enc_iv;
983   struct GNUNET_CRYPTO_EcdhePublicKey *ecdh_key;
984   struct ParallelLookup *parallel_lookup;
985   size_t size;
986   char *buf;
987   char *scope;
988   char *lookup_query;
989
990   handle->lookup_request = NULL;
991   if (1 != rd_count)
992   {
993     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
994                 "Number of keys %d != 1.",
995                 rd_count);
996     cleanup_exchange_handle (handle);
997     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
998     return;
999   }
1000
1001   //Decrypt
1002   ecdh_key = (struct GNUNET_CRYPTO_EcdhePublicKey *)rd->data;
1003
1004   buf = GNUNET_malloc (rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1005
1006   //Calculate symmetric key from ecdh parameters
1007   GNUNET_assert (GNUNET_OK == 
1008                  GNUNET_CRYPTO_ecdsa_ecdh (&handle->aud_privkey,
1009                                            ecdh_key,
1010                                            &new_key_hash));
1011   create_sym_key_from_ecdh (&new_key_hash,
1012                             &enc_key,
1013                             &enc_iv);
1014   size = GNUNET_CRYPTO_symmetric_decrypt (rd->data + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
1015                                           rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey),
1016                                           &enc_key,
1017                                           &enc_iv,
1018                                           buf);
1019
1020   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1021               "Decrypted bytes: %zd Expected bytes: %zd\n",
1022               size, rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey));
1023
1024   scopes = GNUNET_strdup (buf);
1025   GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1026               "Scopes %s\n", scopes);
1027   handle->key = GNUNET_CRYPTO_cpabe_deserialize_key ((void*)(buf + strlen (scopes) + 1),
1028                                          rd->data_size - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)
1029                                          - strlen (scopes) - 1);
1030
1031   for (scope = strtok (scopes, ","); NULL != scope; scope = strtok (NULL, ","))
1032   {
1033     GNUNET_asprintf (&lookup_query,
1034                      "%s.gnu",
1035                      scope);
1036     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1037                 "Looking up %s\n", lookup_query);
1038     parallel_lookup = GNUNET_new (struct ParallelLookup);
1039     parallel_lookup->handle = handle;
1040     parallel_lookup->label = GNUNET_strdup (scope);
1041     parallel_lookup->lookup_request
1042       = GNUNET_GNS_lookup (gns_handle,
1043                            lookup_query,
1044                            &handle->ticket->payload->identity_key,
1045                            GNUNET_GNSRECORD_TYPE_ID_ATTR,
1046                            GNUNET_GNS_LO_LOCAL_MASTER,
1047                            &process_parallel_lookup,
1048                            parallel_lookup);
1049     GNUNET_CONTAINER_DLL_insert (handle->parallel_lookups_head,
1050                                  handle->parallel_lookups_tail,
1051                                  parallel_lookup);
1052   }
1053   handle->kill_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES,3),
1054                                 &abort_parallel_lookups,
1055                                 handle);
1056 }
1057
1058 /**
1059  * Checks a exchange message
1060  *
1061  * @param cls client sending the message
1062  * @param xm message of type `struct ExchangeMessage`
1063  * @return #GNUNET_OK if @a xm is well-formed
1064  */
1065 static int
1066 check_exchange_message (void *cls,
1067                         const struct ExchangeMessage *xm)
1068 {
1069   uint16_t size;
1070
1071   size = ntohs (xm->header.size);
1072   if (size <= sizeof (struct ExchangeMessage))
1073   {
1074     GNUNET_break (0);
1075     return GNUNET_SYSERR;
1076   }
1077   return GNUNET_OK;
1078 }
1079
1080 /**
1081  *
1082  * Handler for exchange message
1083  *
1084  * @param cls unused
1085  * @param client who sent the message
1086  * @param message the message
1087  */
1088 static void
1089 handle_exchange_message (void *cls,
1090                          const struct ExchangeMessage *xm)
1091 {
1092   struct ExchangeHandle *xchange_handle;
1093   struct GNUNET_SERVICE_Client *client = cls;
1094   const char *ticket;
1095   char *lookup_query;
1096
1097   ticket = (const char *) &xm[1];
1098   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1099               "Received EXCHANGE of `%s' from client\n",
1100               ticket);
1101   xchange_handle = GNUNET_malloc (sizeof (struct ExchangeHandle));
1102   xchange_handle->aud_privkey = xm->aud_privkey;
1103   xchange_handle->r_id = xm->id;
1104   if (GNUNET_SYSERR == ticket_parse (ticket,
1105                                      &xchange_handle->aud_privkey,
1106                                      &xchange_handle->ticket))
1107   {
1108     GNUNET_free (xchange_handle);
1109     GNUNET_SERVICE_client_drop (client);
1110     return;
1111   }
1112   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for ABE key under %s\n",
1113               xchange_handle->ticket->payload->label);
1114   GNUNET_asprintf (&lookup_query,
1115                    "%s.gnu",
1116                    xchange_handle->ticket->payload->label);
1117   GNUNET_SERVICE_client_continue (client);
1118   xchange_handle->client = client;
1119   xchange_handle->token = token_create (&xchange_handle->ticket->payload->identity_key,
1120                                         &xchange_handle->ticket->payload->identity_key);
1121   xchange_handle->lookup_request
1122     = GNUNET_GNS_lookup (gns_handle,
1123                          lookup_query,
1124                          &xchange_handle->ticket->payload->identity_key,
1125                          GNUNET_GNSRECORD_TYPE_ABE_KEY,
1126                          GNUNET_GNS_LO_LOCAL_MASTER,
1127                          &process_lookup_result,
1128                          xchange_handle);
1129   GNUNET_free (lookup_query);
1130
1131 }
1132
1133 /**
1134  * Checks an issue message
1135  *
1136  * @param cls client sending the message
1137  * @param im message of type `struct IssueMessage`
1138  * @return #GNUNET_OK if @a im is well-formed
1139  */
1140 static int
1141 check_issue_message(void *cls,
1142                     const struct IssueMessage *im)
1143 {
1144   uint16_t size;
1145
1146   size = ntohs (im->header.size);
1147   if (size <= sizeof (struct IssueMessage))
1148   {
1149     GNUNET_break (0);
1150     return GNUNET_SYSERR;
1151   }
1152   scopes = (char *) &im[1];
1153   if ('\0' != scopes[size - sizeof (struct IssueMessage) - 1])
1154   {
1155     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1156                 "Malformed scopes received!\n");
1157     GNUNET_break (0);
1158     return GNUNET_SYSERR;
1159   }
1160   return GNUNET_OK;
1161 }
1162
1163 void
1164 attr_collect_task (void *cls)
1165 {
1166   struct IssueHandle *issue_handle = cls;
1167
1168   issue_handle->ns_it = GNUNET_NAMESTORE_zone_iteration_start (ns_handle,
1169                                                                &issue_handle->iss_key,
1170                                                                &attr_collect_error,
1171                                                                issue_handle,
1172                                                                &attr_collect,
1173                                                                issue_handle,
1174                                                                &attr_collect_finished,
1175                                                                issue_handle);
1176 }
1177
1178 void
1179 store_bootstrap_cont (void *cls,
1180                       int32_t success,
1181                       const char *emsg)
1182 {
1183   if (GNUNET_SYSERR == success)
1184   {
1185     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1186                 "Failed to bootstrap ABE master %s\n",
1187                 emsg);
1188     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1189     return;
1190   }
1191   GNUNET_SCHEDULER_add_now (&attr_collect_task, cls);
1192 }
1193
1194 void
1195 store_bootstrap_task (void *cls)
1196 {
1197   struct IssueHandle *issue_handle = cls;
1198   struct GNUNET_GNSRECORD_Data rd[1];
1199
1200   rd[0].data_size = GNUNET_CRYPTO_cpabe_serialize_master_key (issue_handle->abe_key,
1201                                                               (void**)&rd[0].data);
1202   rd[0].record_type = GNUNET_GNSRECORD_TYPE_ABE_MASTER;
1203   rd[0].flags = GNUNET_GNSRECORD_RF_NONE | GNUNET_GNSRECORD_RF_PRIVATE;
1204   rd[0].expiration_time = GNUNET_TIME_UNIT_HOURS.rel_value_us; //TODO sane?
1205   issue_handle->ns_qe = GNUNET_NAMESTORE_records_store (ns_handle,
1206                                                         &issue_handle->iss_key,
1207                                                         "+",
1208                                                         1,
1209                                                         rd,
1210                                                         &store_bootstrap_cont,
1211                                                         issue_handle);
1212 }
1213
1214 void
1215 abe_key_lookup_error (void *cls)
1216 {
1217   GNUNET_SCHEDULER_add_now (&do_shutdown, cls);
1218 }
1219
1220 void
1221 abe_key_lookup_result (void *cls,
1222                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1223                        const char *label,
1224                        unsigned int rd_count,
1225                        const struct GNUNET_GNSRECORD_Data *rd)
1226 {
1227   struct IssueHandle *handle = cls;
1228   int i;
1229
1230   for (i=0;i<rd_count;i++) {
1231     if (GNUNET_GNSRECORD_TYPE_ABE_MASTER != rd[i].record_type)
1232       continue;
1233     handle->abe_key = GNUNET_CRYPTO_cpabe_deserialize_master_key ((void**)rd[i].data,
1234                                                                   rd[i].data_size);
1235     GNUNET_SCHEDULER_add_now (&attr_collect_task, handle);
1236     return;
1237   }
1238
1239   //No ABE master found, bootstrapping...
1240   handle->abe_key = GNUNET_CRYPTO_cpabe_create_master_key ();
1241   GNUNET_SCHEDULER_add_now (&store_bootstrap_task, handle);
1242 }
1243
1244 /**
1245  *
1246  * Handler for issue message
1247  *
1248  * @param cls unused
1249  * @param client who sent the message
1250  * @param message the message
1251  */
1252 static void
1253 handle_issue_message (void *cls,
1254                       const struct IssueMessage *im)
1255 {
1256   const char *scopes;
1257   char *scopes_tmp;
1258   char *scope;
1259   const char *v_attrs;
1260   uint64_t rnd_key;
1261   struct GNUNET_HashCode key;
1262   struct IssueHandle *issue_handle;
1263   struct VerifiedAttributeEntry *vattr_entry;
1264   struct GNUNET_SERVICE_Client *client = cls;
1265
1266   scopes = (const char *) &im[1];
1267   v_attrs = (const char *) &im[1] + ntohl(im->scope_len);
1268   issue_handle = GNUNET_malloc (sizeof (struct IssueHandle));
1269   issue_handle->attr_map = GNUNET_CONTAINER_multihashmap_create (5,
1270                                                                  GNUNET_NO);
1271   scopes_tmp = GNUNET_strdup (scopes);
1272
1273   for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1274   {
1275     GNUNET_CRYPTO_hash (scope,
1276                         strlen (scope),
1277                         &key);
1278     GNUNET_CONTAINER_multihashmap_put (issue_handle->attr_map,
1279                                        &key,
1280                                        scope,
1281                                        GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1282   }
1283   GNUNET_free (scopes_tmp);
1284   /*scopes_tmp = GNUNET_strdup (v_attrs);
1285
1286   for (scope = strtok (scopes_tmp, ","); NULL != scope; scope = strtok (NULL, ","))
1287   {
1288     vattr_entry = GNUNET_new (struct VerifiedAttributeEntry);
1289     vattr_entry->name = GNUNET_strdup (scope);
1290     GNUNET_CONTAINER_DLL_insert (issue_handle->v_attr_head,
1291                                  issue_handle->v_attr_tail,
1292                                  vattr_entry);
1293   }
1294   GNUNET_free (scopes_tmp);*/
1295
1296
1297
1298   issue_handle->r_id = im->id;
1299   issue_handle->aud_key = im->aud_key;
1300   issue_handle->iss_key = im->iss_key;
1301   GNUNET_CRYPTO_ecdsa_key_get_public (&im->iss_key,
1302                                       &issue_handle->iss_pkey);
1303   issue_handle->expiration = GNUNET_TIME_absolute_ntoh (im->expiration);
1304   issue_handle->nonce = ntohl (im->nonce);
1305   GNUNET_SERVICE_client_continue (client);
1306   issue_handle->client = client;
1307   issue_handle->scopes = GNUNET_strdup (scopes);
1308   issue_handle->token = token_create (&issue_handle->iss_pkey,
1309                                       &issue_handle->aud_key);
1310   rnd_key =
1311     GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG,
1312                               UINT64_MAX);
1313   GNUNET_STRINGS_base64_encode ((char*)&rnd_key,
1314                                 sizeof (uint64_t),
1315                                 &issue_handle->label);
1316   issue_handle->ns_qe = GNUNET_NAMESTORE_records_lookup (ns_handle,
1317                                                          &issue_handle->iss_key,
1318                                                          "+",
1319                                                          &abe_key_lookup_error,
1320                                                          issue_handle,
1321                                                          &abe_key_lookup_result,
1322                                                          issue_handle);
1323 }
1324
1325
1326 /**
1327  * Main function that will be run
1328  *
1329  * @param cls closure
1330  * @param args remaining command-line arguments
1331  * @param cfgfile name of the configuration file used (for saving, can be NULL)
1332  * @param c configuration
1333  */
1334 static void
1335 run (void *cls,
1336      const struct GNUNET_CONFIGURATION_Handle *c,
1337      struct GNUNET_SERVICE_Handle *server)
1338 {
1339   cfg = c;
1340
1341   stats = GNUNET_STATISTICS_create ("identity-provider", cfg);
1342
1343   //Connect to identity and namestore services
1344   ns_handle = GNUNET_NAMESTORE_connect (cfg);
1345   if (NULL == ns_handle)
1346   {
1347     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to namestore");
1348   }
1349
1350   gns_handle = GNUNET_GNS_connect (cfg);
1351   if (NULL == gns_handle)
1352   {
1353     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1354   }
1355   credential_handle = GNUNET_CREDENTIAL_connect (cfg);
1356   if (NULL == credential_handle)
1357   {
1358     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to credential");
1359   }
1360   identity_handle = GNUNET_IDENTITY_connect (cfg,
1361                                              NULL,
1362                                              NULL);
1363
1364   if (GNUNET_OK ==
1365       GNUNET_CONFIGURATION_get_value_time (cfg,
1366                                            "identity-provider",
1367                                            "TOKEN_EXPIRATION_INTERVAL",
1368                                            &token_expiration_interval))
1369   {
1370     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1371                 "Time window for zone iteration: %s\n",
1372                 GNUNET_STRINGS_relative_time_to_string (token_expiration_interval,
1373                                                         GNUNET_YES));
1374   } else {
1375     token_expiration_interval = DEFAULT_TOKEN_EXPIRATION_INTERVAL;
1376   }
1377
1378   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1379 }
1380
1381 /**
1382  * Called whenever a client is disconnected.
1383  *
1384  * @param cls closure
1385  * @param client identification of the client
1386  * @param app_ctx @a client
1387  */
1388 static void
1389 client_disconnect_cb (void *cls,
1390                       struct GNUNET_SERVICE_Client *client,
1391                       void *app_ctx)
1392 {
1393   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1394               "Client %p disconnected\n",
1395               client);
1396 }
1397
1398
1399 /**
1400  * Add a client to our list of active clients.
1401  *
1402  * @param cls NULL
1403  * @param client client to add
1404  * @param mq message queue for @a client
1405  * @return internal namestore client structure for this client
1406  */
1407 static void *
1408 client_connect_cb (void *cls,
1409                    struct GNUNET_SERVICE_Client *client,
1410                    struct GNUNET_MQ_Handle *mq)
1411 {
1412   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1413               "Client %p connected\n",
1414               client);
1415   return client;
1416 }
1417
1418
1419
1420 /**
1421  * Define "main" method using service macro.
1422  */
1423 GNUNET_SERVICE_MAIN
1424 ("identity-provider",
1425  GNUNET_SERVICE_OPTION_NONE,
1426  &run,
1427  &client_connect_cb,
1428  &client_disconnect_cb,
1429  NULL,
1430  GNUNET_MQ_hd_var_size (issue_message,
1431                         GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_ISSUE,
1432                         struct IssueMessage,
1433                         NULL),
1434  GNUNET_MQ_hd_var_size (exchange_message,
1435                         GNUNET_MESSAGE_TYPE_IDENTITY_PROVIDER_EXCHANGE,
1436                         struct ExchangeMessage,
1437                         NULL),
1438  GNUNET_MQ_handler_end());
1439 /* end of gnunet-service-identity-provider.c */