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