6c94f1c886ab6fed98e8546557457dc374be5dd4
[oweals/gnunet.git] / src / identity / gnunet-service-identity.c
1 /*
2   This file is part of GNUnet.
3   (C) 2013 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., 59 Temple Place - Suite 330,
18   Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file identity/gnunet-service-identity.c
23  * @brief identity management service
24  * @author Christian Grothoff
25  *
26  * The purpose of this service is to manage private keys that
27  * represent the various egos/pseudonyms/identities of a GNUnet user.
28  *
29  * FIXME:
30  * - hint for 'end of initial list' is not implemented
31  *   (might ALSO be missing in client library!)
32  */
33 #include "platform.h"
34 #include "gnunet_util_lib.h"
35 #include "gnunet_constants.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_statistics_service.h"
38 #include "gnunet_identity_service.h"
39 #include "identity.h"
40
41
42 /**
43  * Information we keep about each ego.
44  */
45 struct Ego
46 {
47
48   /**
49    * We keep egos in a DLL.
50    */ 
51   struct Ego *next;
52
53   /**
54    * We keep egos in a DLL.
55    */ 
56   struct Ego *prev;
57
58   /**
59    * Private key of the ego.
60    */
61   struct GNUNET_CRYPTO_EccPrivateKey *pk;
62
63   /**
64    * String identifier for the ego.
65    */
66   char *identifier;
67
68 };
69
70
71 /**
72  * Handle to our current configuration.
73  */
74 static const struct GNUNET_CONFIGURATION_Handle *cfg;
75
76 /**
77  * Handle to subsystem configuration which for each subsystem contains
78  * the name of the default ego.
79  */
80 static struct GNUNET_CONFIGURATION_Handle *subsystem_cfg;
81
82 /**
83  * Handle to the statistics service.
84  */
85 static struct GNUNET_STATISTICS_Handle *stats;
86
87 /**
88  * Notification context, simplifies client broadcasts.
89  */
90 static struct GNUNET_SERVER_NotificationContext *nc;
91
92 /**
93  * Directory where we store the identities.
94  */
95 static char *ego_directory;
96
97 /**
98  * Configuration file name where subsystem information is kept.
99  */
100 static char *subsystem_cfg_file;
101
102 /**
103  * Head of DLL of all egos.
104  */
105 static struct Ego *ego_head;
106
107 /**
108  * Tail of DLL of all egos.
109  */
110 static struct Ego *ego_tail;
111
112
113 /**
114  * Get the name of the file we use to store a given ego.
115  *
116  * @param ego ego for which we need the filename
117  * @return full filename for the given ego
118  */
119 static char *
120 get_ego_filename (struct Ego *ego)
121 {
122   char *filename;
123
124   GNUNET_asprintf (&filename,
125                    "%s%s%s",
126                    ego_directory,
127                    DIR_SEPARATOR_STR,
128                    ego->identifier);
129   return filename;
130 }
131
132
133 /**
134  * Task run during shutdown.
135  *
136  * @param cls unused
137  * @param tc unused
138  */
139 static void
140 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
141 {
142   struct Ego *e;
143
144   if (NULL != nc)
145   {
146     GNUNET_SERVER_notification_context_destroy (nc);
147     nc = NULL;
148   }
149   if (NULL != stats)
150   {
151     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
152     stats = NULL;
153   }
154   GNUNET_CONFIGURATION_destroy (subsystem_cfg);
155   subsystem_cfg = NULL;
156   GNUNET_free (subsystem_cfg_file);
157   subsystem_cfg_file = NULL;
158   GNUNET_free (ego_directory);
159   ego_directory = NULL;
160   while (NULL != (e = ego_head))
161   {
162     GNUNET_CONTAINER_DLL_remove (ego_head, ego_tail, e);
163     GNUNET_CRYPTO_ecc_key_free (e->pk);
164     GNUNET_free (e);
165   }
166 }
167
168
169 /**
170  * Send a result code back to the client.
171  *
172  * @param client client that should receive the result code
173  * @param result_code code to transmit
174  * @param emsg error message to include (or NULL for none)
175  */
176 static void
177 send_result_code (struct GNUNET_SERVER_Client *client,
178                   uint32_t result_code,
179                   const char *emsg)
180 {
181   struct GNUNET_IDENTITY_ResultCodeMessage *rcm;
182   size_t elen;
183
184   if (NULL == emsg)
185     elen = 0;
186   else
187     elen = strlen (emsg) + 1;
188   rcm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) + elen);
189   rcm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE);
190   rcm->header.size = htons (sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) + elen);
191   rcm->result_code = htonl (result_code);
192   memcpy (&rcm[1], emsg, elen);
193   GNUNET_SERVER_notification_context_unicast (nc, client, &rcm->header, GNUNET_YES);  
194   GNUNET_free (rcm);
195 }
196
197
198 /**
199  * Create an update message with information about the current state of an ego.
200  *
201  * @param ego ego to create message for
202  * @return corresponding update message
203  */
204 static struct GNUNET_IDENTITY_UpdateMessage *
205 create_update_message (struct Ego *ego)
206 {
207   struct GNUNET_IDENTITY_UpdateMessage *um;
208   char *str;
209   uint16_t pk_len;
210   size_t name_len;
211   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
212
213   name_len = (NULL == ego->identifier) ? 0 : (strlen (ego->identifier) + 1);
214   enc = GNUNET_CRYPTO_ecc_encode_key (ego->pk);
215   pk_len = ntohs (enc->size);
216   um = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_UpdateMessage) + pk_len + name_len);
217   um->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
218   um->header.size = htons (sizeof (struct GNUNET_IDENTITY_UpdateMessage) + pk_len + name_len);
219   um->name_len = htons (name_len);
220   um->pk_len = htons (pk_len);
221   str = (char *) &um[1];
222   memcpy (str, enc, pk_len);
223   memcpy (&str[pk_len], ego->identifier, name_len);
224   GNUNET_free (enc);
225   return um;
226 }
227
228
229 /**
230  * Create a set default message with information about the current state of an ego.
231  *
232  * @param ego ego to create message for
233  * @param servicename name of the service to provide in the message
234  * @return corresponding set default message
235  */
236 static struct GNUNET_IDENTITY_SetDefaultMessage *
237 create_set_default_message (struct Ego *ego,
238                             const char *servicename)
239 {
240   struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
241   char *str;
242   uint16_t pk_len;
243   size_t name_len;
244   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
245
246   name_len = (NULL == servicename) ? 0 : (strlen (servicename) + 1);
247   enc = GNUNET_CRYPTO_ecc_encode_key (ego->pk);
248   pk_len = ntohs (enc->size);
249   sdm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) + pk_len + name_len);
250   sdm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
251   sdm->header.size = htons (sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) + pk_len + name_len);
252   sdm->name_len = htons (name_len);
253   sdm->pk_len = htons (pk_len);
254   str = (char *) &sdm[1];
255   memcpy (str, enc, pk_len);
256   memcpy (&str[pk_len], servicename, name_len);
257   GNUNET_free (enc);
258   return sdm;
259 }
260
261
262 /**
263  * Handler for START message from client, sends information
264  * about all identities to the client immediately and 
265  * adds the client to the notification context for future
266  * updates.
267  *
268  * @param cls unused
269  * @param client who sent the message
270  * @param message the message received
271  */
272 static void
273 handle_start_message (void *cls, struct GNUNET_SERVER_Client *client,
274                       const struct GNUNET_MessageHeader *message)
275 {
276   struct GNUNET_IDENTITY_UpdateMessage *um;
277   struct Ego *ego;
278
279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
280               "Received START message from client\n");
281   GNUNET_SERVER_notification_context_add (nc, client);
282   for (ego = ego_head; NULL != ego; ego = ego->next)
283   {
284     um = create_update_message (ego);
285     GNUNET_SERVER_notification_context_unicast (nc, client, &um->header, GNUNET_YES);
286     GNUNET_free (um);
287   }
288   GNUNET_SERVER_receive_done (client, GNUNET_OK);
289 }
290
291
292 /**
293  * Handler for GET_DEFAULT message from client, returns
294  * default identity for some service.
295  *
296  * @param cls unused
297  * @param client who sent the message
298  * @param message the message received
299  */
300 static void
301 handle_get_default_message (void *cls, struct GNUNET_SERVER_Client *client,
302                             const struct GNUNET_MessageHeader *message)
303 {
304   const struct GNUNET_IDENTITY_GetDefaultMessage *gdm;
305   struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
306   uint16_t size;
307   uint16_t name_len;
308   struct Ego *ego;
309   const char *name;
310   char *identifier;
311
312   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
313               "Received GET_DEFAULT message from client\n");
314   size = ntohs (message->size);
315   if (size <= sizeof (struct GNUNET_IDENTITY_GetDefaultMessage))
316   {
317     GNUNET_break (0);
318     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
319     return;
320   }
321   gdm = (const struct GNUNET_IDENTITY_GetDefaultMessage *) message;
322   name = (const char *) &gdm[1];
323   name_len = ntohs (gdm->name_len);
324   if ( (name_len + sizeof (struct GNUNET_IDENTITY_GetDefaultMessage) != size) ||
325        (0 != ntohs (gdm->reserved)) ||
326        ('\0' != name[name_len - 1]) )
327   {
328     GNUNET_break (0);
329     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
330     return;
331   }
332   if (GNUNET_OK !=
333       GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
334                                              name,
335                                              "DEFAULT_IDENTIFIER",
336                                              &identifier))
337   {
338     send_result_code (client, 1, gettext_noop ("no default known"));
339     GNUNET_SERVER_receive_done (client, GNUNET_OK);   
340     return;
341   }
342   for (ego = ego_head; NULL != ego; ego = ego->next)
343   {
344     if (0 == strcmp (ego->identifier,
345                      identifier))
346     {
347       sdm = create_set_default_message (ego,
348                                         name);
349       GNUNET_SERVER_notification_context_broadcast (nc, &sdm->header, GNUNET_YES);
350       GNUNET_free (sdm);
351       GNUNET_SERVER_receive_done (client, GNUNET_OK);
352       return;
353     }
354   }
355   send_result_code (client, 1, 
356                     gettext_noop ("default configured, but ego unknown (internal error)"));
357   GNUNET_SERVER_receive_done (client, GNUNET_OK);
358 }
359
360
361 /**
362  * Compare the given two private keys for equality.
363  * 
364  * @param pk1 one private key
365  * @param pk2 another private key
366  * @return 0 if the keys are equal
367  */
368 static int
369 key_cmp (const struct GNUNET_CRYPTO_EccPrivateKey *pk1,
370          const struct GNUNET_CRYPTO_EccPrivateKey *pk2)
371 {
372   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded p1;
373   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded p2;
374   
375   GNUNET_CRYPTO_ecc_key_get_public (pk1, &p1);
376   GNUNET_CRYPTO_ecc_key_get_public (pk2, &p2);
377   return memcmp (&p1, &p2, sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
378 }
379
380
381 /**
382  * Handler for SET_DEFAULT message from client, updates
383  * default identity for some service.
384  *
385  * @param cls unused
386  * @param client who sent the message
387  * @param message the message received
388  */
389 static void
390 handle_set_default_message (void *cls, struct GNUNET_SERVER_Client *client,
391                             const struct GNUNET_MessageHeader *message)
392 {
393   const struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
394   uint16_t size;
395   uint16_t name_len;
396   uint16_t pk_len;
397   struct Ego *ego;
398   const char *str;
399   struct GNUNET_CRYPTO_EccPrivateKey *pk;
400
401   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
402               "Received SET_DEFAULT message from client\n");
403   size = ntohs (message->size);
404   if (size <= sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
405   {
406     GNUNET_break (0);
407     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
408     return;
409   }
410   sdm = (const struct GNUNET_IDENTITY_SetDefaultMessage *) message;
411   name_len = ntohs (sdm->name_len);
412   pk_len = ntohs (sdm->pk_len);
413   str = (const char *) &sdm[1];
414   if ( (name_len + pk_len + sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) != size) ||
415        (NULL == (pk = GNUNET_CRYPTO_ecc_decode_key (str, pk_len, GNUNET_YES))) )
416   {
417     GNUNET_break (0);
418     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
419     return;
420   }
421   str = &str[pk_len];
422   if ('\0' != str[name_len - 1])
423   {
424     GNUNET_break (0);
425     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
426     return;
427   }
428   for (ego = ego_head; NULL != ego; ego = ego->next)
429   {
430     if (0 == key_cmp (ego->pk,
431                       pk))
432     {
433       GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
434                                              str,
435                                              "DEFAULT_IDENTIFIER",
436                                              ego->identifier);
437       if (GNUNET_OK != 
438           GNUNET_CONFIGURATION_write (subsystem_cfg,
439                                       subsystem_cfg_file))
440         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
441                     _("Failed to write subsystem default identifier map to `%s'.\n"),
442                     subsystem_cfg_file);
443       send_result_code (client, 0, NULL);
444       GNUNET_SERVER_receive_done (client, GNUNET_OK);
445       GNUNET_CRYPTO_ecc_key_free (pk);
446       return;
447     }
448   }  
449   send_result_code (client, 1, _("Unknown ego specified for service (internal error)"));
450   GNUNET_SERVER_receive_done (client, GNUNET_OK);
451   GNUNET_CRYPTO_ecc_key_free (pk);
452 }
453
454
455 /**
456  * Send an updated message for the given ego to all listeners.
457  *
458  * @param ego ego to send the update for
459  */
460 static void
461 notify_listeners (struct Ego *ego)
462 {
463   struct GNUNET_IDENTITY_UpdateMessage *um;
464
465   um = create_update_message (ego);
466   GNUNET_SERVER_notification_context_broadcast (nc, &um->header, GNUNET_YES);
467   GNUNET_free (um);
468 }
469
470
471 /**
472  * Handler for CREATE message from client, creates
473  * new identity.
474  *
475  * @param cls unused
476  * @param client who sent the message
477  * @param message the message received
478  */
479 static void
480 handle_create_message (void *cls, struct GNUNET_SERVER_Client *client,
481                        const struct GNUNET_MessageHeader *message)
482 {
483   const struct GNUNET_IDENTITY_CreateRequestMessage *crm;
484   uint16_t size;
485   uint16_t name_len;
486   uint16_t pk_len;
487   struct Ego *ego;
488   const char *pks;
489   const char *str;
490   struct GNUNET_CRYPTO_EccPrivateKey *pk;
491   char *fn;
492
493   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
494               "Received CREATE message from client\n");
495   size = ntohs (message->size);
496   if (size <= sizeof (struct GNUNET_IDENTITY_CreateRequestMessage))
497   {
498     GNUNET_break (0);
499     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
500     return;
501   }
502   crm = (const struct GNUNET_IDENTITY_CreateRequestMessage *) message;
503   name_len = ntohs (crm->name_len);
504   pk_len = ntohs (crm->pk_len);
505   pks = (const char *) &crm[1];
506   if ( (name_len + pk_len + sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) != size) ||
507        (NULL == (pk = GNUNET_CRYPTO_ecc_decode_key (pks, pk_len, GNUNET_YES))) )
508   {
509     GNUNET_break (0);
510     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
511     return;
512   }
513   str = &pks[pk_len];
514   if ('\0' != str[name_len - 1])
515   {
516     GNUNET_break (0);
517     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
518     return;
519   }
520   for (ego = ego_head; NULL != ego; ego = ego->next)
521   {
522     if (0 == strcmp (ego->identifier,
523                      str))
524     {
525       send_result_code (client, 1, gettext_noop ("identifier already in use for another ego"));
526       GNUNET_SERVER_receive_done (client, GNUNET_OK);
527       GNUNET_CRYPTO_ecc_key_free (pk);
528       return;
529     }
530   }
531   ego = GNUNET_new (struct Ego);
532   ego->pk = pk;
533   ego->identifier = GNUNET_strdup (str);
534   GNUNET_CONTAINER_DLL_insert (ego_head,
535                                ego_tail,
536                                ego);
537   send_result_code (client, 0, NULL);
538   fn = get_ego_filename (ego);
539   (void) GNUNET_DISK_directory_create_for_file (fn);
540   if (pk_len !=
541       GNUNET_DISK_fn_write (fn, pks, pk_len,
542                             GNUNET_DISK_PERM_USER_READ |
543                             GNUNET_DISK_PERM_USER_WRITE))
544     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
545                               "write", fn);
546   GNUNET_free (fn);
547   notify_listeners (ego);  
548   GNUNET_SERVER_receive_done (client, GNUNET_OK);
549 }
550
551
552 /**
553  * Closure for 'handle_ego_rename'.
554  */
555 struct RenameContext 
556 {
557   /**
558    * Old name.
559    */
560   const char *old_name;
561
562   /**
563    * New name.
564    */
565   const char *new_name;
566 };
567
568
569 /**
570  * An ego was renamed; rename it in all subsystems where it is
571  * currently set as the default.
572  *
573  * @param cls the 'struct RenameContext'
574  * @param section a section in the configuration to process
575  */
576 static void
577 handle_ego_rename (void *cls,
578                    const char *section)
579 {
580   struct RenameContext *rc = cls;
581   char *id;
582
583   if (GNUNET_OK !=
584       GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
585                                              section,
586                                              "DEFAULT_IDENTIFIER",
587                                              &id))
588     return;
589   if (0 != strcmp (id, rc->old_name))
590   {
591     GNUNET_free (id);  
592     return;
593   }
594   GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
595                                          section,
596                                          "DEFAULT_IDENTIFIER",
597                                          rc->new_name);
598   GNUNET_free (id);  
599 }
600
601
602 /**
603  * Handler for RENAME message from client, creates
604  * new identity.
605  *
606  * @param cls unused
607  * @param client who sent the message
608  * @param message the message received
609  */
610 static void
611 handle_rename_message (void *cls, struct GNUNET_SERVER_Client *client,
612                        const struct GNUNET_MessageHeader *message)
613 {
614   const struct GNUNET_IDENTITY_RenameMessage *rm;
615   uint16_t size;
616   uint16_t old_name_len;
617   uint16_t new_name_len;
618   struct Ego *ego;
619   const char *old_name;
620   const char *new_name;
621   struct RenameContext rename_ctx;
622   char *fn_old;
623   char *fn_new;
624
625   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
626               "Received RENAME message from client\n");
627   size = ntohs (message->size);
628   if (size <= sizeof (struct GNUNET_IDENTITY_RenameMessage))
629   {
630     GNUNET_break (0);
631     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
632     return;
633   }
634   rm = (const struct GNUNET_IDENTITY_RenameMessage *) message;
635   old_name_len = ntohs (rm->old_name_len);
636   new_name_len = ntohs (rm->new_name_len);
637   old_name = (const char *) &rm[1];
638   new_name = &old_name[old_name_len];
639   if ( (old_name_len + new_name_len + sizeof (struct GNUNET_IDENTITY_RenameMessage) != size) ||
640        ('\0' != old_name[old_name_len - 1]) ||
641        ('\0' != new_name[new_name_len - 1]) )
642   {
643     GNUNET_break (0);
644     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
645     return;
646   }
647
648   /* check if new name is already in use */
649   for (ego = ego_head; NULL != ego; ego = ego->next)
650   {
651     if (0 == strcmp (ego->identifier,
652                      new_name))
653     {
654       send_result_code (client, 1, gettext_noop ("target name already exists"));
655       GNUNET_SERVER_receive_done (client, GNUNET_OK);      
656       return;
657     }
658   }
659
660   /* locate old name and, if found, perform rename */
661   for (ego = ego_head; NULL != ego; ego = ego->next)
662   {
663     if (0 == strcmp (ego->identifier,
664                      old_name))
665     {
666       fn_old = get_ego_filename (ego);
667       GNUNET_free (ego->identifier);
668       rename_ctx.old_name = old_name;
669       rename_ctx.new_name = new_name;
670       GNUNET_CONFIGURATION_iterate_sections (subsystem_cfg,
671                                              &handle_ego_rename,
672                                              &rename_ctx);
673       if (GNUNET_OK != 
674           GNUNET_CONFIGURATION_write (subsystem_cfg,
675                                       subsystem_cfg_file))
676         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
677                     _("Failed to write subsystem default identifier map to `%s'.\n"),
678                     subsystem_cfg_file);
679       ego->identifier = GNUNET_strdup (new_name);
680       fn_new = get_ego_filename (ego);      
681       if (0 != RENAME (fn_old, fn_new))
682         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rename", fn_old);
683       GNUNET_free (fn_old);
684       GNUNET_free (fn_new);
685       notify_listeners (ego);
686       send_result_code (client, 0, NULL);
687       GNUNET_SERVER_receive_done (client, GNUNET_OK);
688       return;
689     }
690   }
691
692   /* failed to locate old name */
693   send_result_code (client, 1, gettext_noop ("no matching ego found"));
694   GNUNET_SERVER_receive_done (client, GNUNET_OK);
695 }
696
697
698 /**
699  * An ego was removed, remove it from all subsystems where it is
700  * currently set as the default.
701  *
702  * @param cls name of the removed ego (const char *)
703  * @param section a section in the configuration to process
704  */
705 static void
706 handle_ego_delete (void *cls,
707                    const char *section)
708 {
709   const char *identifier = cls;
710   char *id;
711
712   if (GNUNET_OK !=
713       GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
714                                              section,
715                                              "DEFAULT_IDENTIFIER",
716                                              &id))
717     return;
718   if (0 != strcmp (id, identifier))
719   {
720     GNUNET_free (id);  
721     return;
722   }
723   GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
724                                          section,
725                                          "DEFAULT_IDENTIFIER",
726                                          NULL);
727   GNUNET_free (id);  
728 }
729
730
731 /**
732  * Handler for DELETE message from client, creates
733  * new identity.
734  *
735  * @param cls unused
736  * @param client who sent the message
737  * @param message the message received
738  */
739 static void
740 handle_delete_message (void *cls, struct GNUNET_SERVER_Client *client,
741                        const struct GNUNET_MessageHeader *message)
742 {
743   const struct GNUNET_IDENTITY_DeleteMessage *dm;
744   uint16_t size;
745   uint16_t name_len;
746   struct Ego *ego;
747   const char *name;
748   char *fn;
749
750   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
751               "Received DELETE message from client\n");
752   size = ntohs (message->size);
753   if (size <= sizeof (struct GNUNET_IDENTITY_DeleteMessage))
754   {
755     GNUNET_break (0);
756     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
757     return;
758   }
759   dm = (const struct GNUNET_IDENTITY_DeleteMessage *) message;
760   name = (const char *) &dm[1];
761   name_len = ntohs (dm->name_len);
762   if ( (name_len + sizeof (struct GNUNET_IDENTITY_DeleteMessage) != size) ||
763        (0 != ntohs (dm->reserved)) ||
764        ('\0' != name[name_len - 1]) )
765   {
766     GNUNET_break (0);
767     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
768     return;
769   }
770   for (ego = ego_head; NULL != ego; ego = ego->next)
771   {
772     if (0 == strcmp (ego->identifier,
773                      name))
774     {
775       GNUNET_CONTAINER_DLL_remove (ego_head,
776                                    ego_tail,
777                                    ego);
778       GNUNET_CONFIGURATION_iterate_sections (subsystem_cfg,
779                                              &handle_ego_delete,
780                                              ego->identifier);
781       if (GNUNET_OK != 
782           GNUNET_CONFIGURATION_write (subsystem_cfg,
783                                       subsystem_cfg_file))
784         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
785                     _("Failed to write subsystem default identifier map to `%s'.\n"),
786                     subsystem_cfg_file);
787       fn = get_ego_filename (ego);
788       if (0 != UNLINK (fn))
789         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
790       GNUNET_free (fn);
791       GNUNET_free (ego->identifier);
792       ego->identifier = NULL;
793       notify_listeners (ego);
794       GNUNET_CRYPTO_ecc_key_free (ego->pk);
795       GNUNET_free (ego);
796       send_result_code (client, 0, NULL);
797       GNUNET_SERVER_receive_done (client, GNUNET_OK);
798       return;
799     }
800   }
801
802   send_result_code (client, 1, gettext_noop ("no matching ego found"));
803   GNUNET_SERVER_receive_done (client, GNUNET_OK);
804 }
805
806
807 /**
808  * Process the given file from the "EGODIR".  Parses the file
809  * and creates the respective 'struct Ego' in memory.
810  *
811  * @param cls NULL
812  * @param filename name of the file to parse
813  * @return GNUNET_OK to continue to iterate,
814  *  GNUNET_NO to stop iteration with no error,
815  *  GNUNET_SYSERR to abort iteration with error!
816  */
817 static int
818 process_ego_file (void *cls,
819                   const char *filename)
820 {
821   struct Ego *ego;
822   const char *fn;
823
824   fn = strrchr (filename, (int) DIR_SEPARATOR);
825   if (NULL == fn)
826   {
827     GNUNET_break (0);
828     return GNUNET_OK;
829   }
830   ego = GNUNET_new (struct Ego);
831   ego->pk = GNUNET_CRYPTO_ecc_key_create_from_file (filename);
832   if (NULL == ego->pk)
833     {
834       GNUNET_free (ego);
835       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
836                   _("Failed to parse ego information in `%s'\n"),
837                   filename);
838       return GNUNET_OK;
839     }
840   
841   ego->identifier = GNUNET_strdup (fn);
842   GNUNET_CONTAINER_DLL_insert (ego_head,
843                                ego_tail,
844                                ego);
845   return GNUNET_OK;
846 }
847
848
849 /**
850  * Handle network size estimate clients.
851  *
852  * @param cls closure
853  * @param server the initialized server
854  * @param c configuration to use
855  */
856 static void
857 run (void *cls, 
858      struct GNUNET_SERVER_Handle *server,
859      const struct GNUNET_CONFIGURATION_Handle *c)
860 {
861   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
862     {&handle_start_message, NULL,
863      GNUNET_MESSAGE_TYPE_IDENTITY_START, sizeof (struct GNUNET_MessageHeader)},
864     {&handle_get_default_message, NULL,
865      GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT, 0},
866     {&handle_set_default_message, NULL,
867      GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT, 0},
868     {&handle_create_message, NULL,
869      GNUNET_MESSAGE_TYPE_IDENTITY_CREATE, 0},
870     {&handle_rename_message, NULL,
871      GNUNET_MESSAGE_TYPE_IDENTITY_RENAME, 0},
872     {&handle_delete_message, NULL,
873      GNUNET_MESSAGE_TYPE_IDENTITY_DELETE, 0},
874     {NULL, NULL, 0, 0}
875   };
876
877   cfg = c;
878   if (GNUNET_OK !=
879       GNUNET_CONFIGURATION_get_value_filename (cfg, "identity",
880                                                "EGODIR",
881                                                &ego_directory))
882   {
883     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "EGODIR");
884     GNUNET_SCHEDULER_shutdown ();
885     return;
886   }
887   if (GNUNET_OK !=
888       GNUNET_CONFIGURATION_get_value_filename (cfg, "identity",
889                                                "SUBSYSTEM_CFG",
890                                                &subsystem_cfg_file))
891   {
892     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "SUBSYSTEM_CFG");
893     GNUNET_SCHEDULER_shutdown ();
894     return;
895   }
896   subsystem_cfg = GNUNET_CONFIGURATION_create ();
897   if ( (GNUNET_YES ==
898         GNUNET_DISK_file_test (subsystem_cfg_file)) &&
899        (GNUNET_OK != 
900         GNUNET_CONFIGURATION_parse (subsystem_cfg,
901                                     subsystem_cfg_file)) )
902   {
903     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
904                 _("Failed to parse subsystem identity configuration file `%s'\n"),
905                 subsystem_cfg_file);
906     GNUNET_SCHEDULER_shutdown ();
907     return;
908   }
909   stats = GNUNET_STATISTICS_create ("identity", cfg);
910   GNUNET_SERVER_add_handlers (server, handlers);
911   nc = GNUNET_SERVER_notification_context_create (server, 1);
912   GNUNET_DISK_directory_scan (ego_directory,
913                               &process_ego_file,
914                               NULL);
915   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
916                                 NULL);
917 }
918
919
920 /**
921  * The main function for the network size estimation service.
922  *
923  * @param argc number of arguments from the command line
924  * @param argv command line arguments
925  * @return 0 ok, 1 on error
926  */
927 int
928 main (int argc, char *const *argv)
929 {
930   return (GNUNET_OK ==
931           GNUNET_SERVICE_run (argc, argv, "identity", 
932                               GNUNET_SERVICE_OPTION_NONE,
933                               &run, NULL)) ? 0 : 1;
934 }
935
936
937 /* end of gnunet-service-identity.c */