45c088e447f96004ef34f622ee830c9bdc2282da
[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 GNUNET_IDENTITY_UpdateMessage ume;
274   struct Ego *ego;
275
276   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
277               "Received START message from client\n");
278   GNUNET_SERVER_notification_context_add (nc, client);
279   for (ego = ego_head; NULL != ego; ego = ego->next)
280   {
281     um = create_update_message (ego);
282     GNUNET_SERVER_notification_context_unicast (nc, client, &um->header, GNUNET_YES);
283     GNUNET_free (um);
284   }
285   ume.header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
286   ume.header.size = htons (sizeof (struct GNUNET_IDENTITY_UpdateMessage));
287   ume.pk_len = htons (0);
288   ume.name_len = htons (0);
289   GNUNET_SERVER_notification_context_unicast (nc, client, &ume.header, GNUNET_YES);  
290   GNUNET_SERVER_receive_done (client, GNUNET_OK);
291 }
292
293
294 /**
295  * Handler for GET_DEFAULT message from client, returns
296  * default identity for some service.
297  *
298  * @param cls unused
299  * @param client who sent the message
300  * @param message the message received
301  */
302 static void
303 handle_get_default_message (void *cls, struct GNUNET_SERVER_Client *client,
304                             const struct GNUNET_MessageHeader *message)
305 {
306   const struct GNUNET_IDENTITY_GetDefaultMessage *gdm;
307   struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
308   uint16_t size;
309   uint16_t name_len;
310   struct Ego *ego;
311   const char *name;
312   char *identifier;
313
314   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
315               "Received GET_DEFAULT message from client\n");
316   size = ntohs (message->size);
317   if (size <= sizeof (struct GNUNET_IDENTITY_GetDefaultMessage))
318   {
319     GNUNET_break (0);
320     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
321     return;
322   }
323   gdm = (const struct GNUNET_IDENTITY_GetDefaultMessage *) message;
324   name = (const char *) &gdm[1];
325   name_len = ntohs (gdm->name_len);
326   if ( (name_len + sizeof (struct GNUNET_IDENTITY_GetDefaultMessage) != size) ||
327        (0 != ntohs (gdm->reserved)) ||
328        ('\0' != name[name_len - 1]) )
329   {
330     GNUNET_break (0);
331     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
332     return;
333   }
334   if (GNUNET_OK !=
335       GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
336                                              name,
337                                              "DEFAULT_IDENTIFIER",
338                                              &identifier))
339   {
340     send_result_code (client, 1, gettext_noop ("no default known"));
341     GNUNET_SERVER_receive_done (client, GNUNET_OK);   
342     return;
343   }
344   for (ego = ego_head; NULL != ego; ego = ego->next)
345   {
346     if (0 == strcmp (ego->identifier,
347                      identifier))
348     {
349       sdm = create_set_default_message (ego,
350                                         name);
351       GNUNET_SERVER_notification_context_broadcast (nc, &sdm->header, GNUNET_YES);
352       GNUNET_free (sdm);
353       GNUNET_SERVER_receive_done (client, GNUNET_OK);
354       return;
355     }
356   }
357   send_result_code (client, 1, 
358                     gettext_noop ("default configured, but ego unknown (internal error)"));
359   GNUNET_SERVER_receive_done (client, GNUNET_OK);
360 }
361
362
363 /**
364  * Compare the given two private keys for equality.
365  * 
366  * @param pk1 one private key
367  * @param pk2 another private key
368  * @return 0 if the keys are equal
369  */
370 static int
371 key_cmp (const struct GNUNET_CRYPTO_EccPrivateKey *pk1,
372          const struct GNUNET_CRYPTO_EccPrivateKey *pk2)
373 {
374   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded p1;
375   struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded p2;
376   
377   GNUNET_CRYPTO_ecc_key_get_public (pk1, &p1);
378   GNUNET_CRYPTO_ecc_key_get_public (pk2, &p2);
379   return memcmp (&p1, &p2, sizeof (struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded));
380 }
381
382
383 /**
384  * Handler for SET_DEFAULT message from client, updates
385  * default identity for some service.
386  *
387  * @param cls unused
388  * @param client who sent the message
389  * @param message the message received
390  */
391 static void
392 handle_set_default_message (void *cls, struct GNUNET_SERVER_Client *client,
393                             const struct GNUNET_MessageHeader *message)
394 {
395   const struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
396   uint16_t size;
397   uint16_t name_len;
398   uint16_t pk_len;
399   struct Ego *ego;
400   const char *str;
401   struct GNUNET_CRYPTO_EccPrivateKey *pk;
402
403   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
404               "Received SET_DEFAULT message from client\n");
405   size = ntohs (message->size);
406   if (size <= sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
407   {
408     GNUNET_break (0);
409     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
410     return;
411   }
412   sdm = (const struct GNUNET_IDENTITY_SetDefaultMessage *) message;
413   name_len = ntohs (sdm->name_len);
414   pk_len = ntohs (sdm->pk_len);
415   str = (const char *) &sdm[1];
416   if ( (name_len + pk_len + sizeof (struct GNUNET_IDENTITY_SetDefaultMessage) != size) ||
417        (NULL == (pk = GNUNET_CRYPTO_ecc_decode_key (str, pk_len, GNUNET_YES))) )
418   {
419     GNUNET_break (0);
420     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
421     return;
422   }
423   str = &str[pk_len];
424   if ('\0' != str[name_len - 1])
425   {
426     GNUNET_break (0);
427     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
428     return;
429   }
430   for (ego = ego_head; NULL != ego; ego = ego->next)
431   {
432     if (0 == key_cmp (ego->pk,
433                       pk))
434     {
435       GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
436                                              str,
437                                              "DEFAULT_IDENTIFIER",
438                                              ego->identifier);
439       if (GNUNET_OK != 
440           GNUNET_CONFIGURATION_write (subsystem_cfg,
441                                       subsystem_cfg_file))
442         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
443                     _("Failed to write subsystem default identifier map to `%s'.\n"),
444                     subsystem_cfg_file);
445       send_result_code (client, 0, NULL);
446       GNUNET_SERVER_receive_done (client, GNUNET_OK);
447       GNUNET_CRYPTO_ecc_key_free (pk);
448       return;
449     }
450   }  
451   send_result_code (client, 1, _("Unknown ego specified for service (internal error)"));
452   GNUNET_SERVER_receive_done (client, GNUNET_OK);
453   GNUNET_CRYPTO_ecc_key_free (pk);
454 }
455
456
457 /**
458  * Send an updated message for the given ego to all listeners.
459  *
460  * @param ego ego to send the update for
461  */
462 static void
463 notify_listeners (struct Ego *ego)
464 {
465   struct GNUNET_IDENTITY_UpdateMessage *um;
466
467   um = create_update_message (ego);
468   GNUNET_SERVER_notification_context_broadcast (nc, &um->header, GNUNET_YES);
469   GNUNET_free (um);
470 }
471
472
473 /**
474  * Handler for CREATE message from client, creates
475  * new identity.
476  *
477  * @param cls unused
478  * @param client who sent the message
479  * @param message the message received
480  */
481 static void
482 handle_create_message (void *cls, struct GNUNET_SERVER_Client *client,
483                        const struct GNUNET_MessageHeader *message)
484 {
485   const struct GNUNET_IDENTITY_CreateRequestMessage *crm;
486   uint16_t size;
487   uint16_t name_len;
488   uint16_t pk_len;
489   struct Ego *ego;
490   const char *pks;
491   const char *str;
492   struct GNUNET_CRYPTO_EccPrivateKey *pk;
493   char *fn;
494
495   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
496               "Received CREATE message from client\n");
497   size = ntohs (message->size);
498   if (size <= sizeof (struct GNUNET_IDENTITY_CreateRequestMessage))
499   {
500     GNUNET_break (0);
501     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
502     return;
503   }
504   crm = (const struct GNUNET_IDENTITY_CreateRequestMessage *) message;
505   name_len = ntohs (crm->name_len);
506   pk_len = ntohs (crm->pk_len);
507   pks = (const char *) &crm[1];
508   if ( (name_len + pk_len + sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) != size) ||
509        (NULL == (pk = GNUNET_CRYPTO_ecc_decode_key (pks, pk_len, GNUNET_YES))) )
510   {
511     GNUNET_break (0);
512     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
513     return;
514   }
515   str = &pks[pk_len];
516   if ('\0' != str[name_len - 1])
517   {
518     GNUNET_break (0);
519     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
520     return;
521   }
522   for (ego = ego_head; NULL != ego; ego = ego->next)
523   {
524     if (0 == strcmp (ego->identifier,
525                      str))
526     {
527       send_result_code (client, 1, gettext_noop ("identifier already in use for another ego"));
528       GNUNET_SERVER_receive_done (client, GNUNET_OK);
529       GNUNET_CRYPTO_ecc_key_free (pk);
530       return;
531     }
532   }
533   ego = GNUNET_new (struct Ego);
534   ego->pk = pk;
535   ego->identifier = GNUNET_strdup (str);
536   GNUNET_CONTAINER_DLL_insert (ego_head,
537                                ego_tail,
538                                ego);
539   send_result_code (client, 0, NULL);
540   fn = get_ego_filename (ego);
541   (void) GNUNET_DISK_directory_create_for_file (fn);
542   if (pk_len !=
543       GNUNET_DISK_fn_write (fn, pks, pk_len,
544                             GNUNET_DISK_PERM_USER_READ |
545                             GNUNET_DISK_PERM_USER_WRITE))
546     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
547                               "write", fn);
548   GNUNET_free (fn);
549   notify_listeners (ego);  
550   GNUNET_SERVER_receive_done (client, GNUNET_OK);
551 }
552
553
554 /**
555  * Closure for 'handle_ego_rename'.
556  */
557 struct RenameContext 
558 {
559   /**
560    * Old name.
561    */
562   const char *old_name;
563
564   /**
565    * New name.
566    */
567   const char *new_name;
568 };
569
570
571 /**
572  * An ego was renamed; rename it in all subsystems where it is
573  * currently set as the default.
574  *
575  * @param cls the 'struct RenameContext'
576  * @param section a section in the configuration to process
577  */
578 static void
579 handle_ego_rename (void *cls,
580                    const char *section)
581 {
582   struct RenameContext *rc = cls;
583   char *id;
584
585   if (GNUNET_OK !=
586       GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
587                                              section,
588                                              "DEFAULT_IDENTIFIER",
589                                              &id))
590     return;
591   if (0 != strcmp (id, rc->old_name))
592   {
593     GNUNET_free (id);  
594     return;
595   }
596   GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
597                                          section,
598                                          "DEFAULT_IDENTIFIER",
599                                          rc->new_name);
600   GNUNET_free (id);  
601 }
602
603
604 /**
605  * Handler for RENAME message from client, creates
606  * new identity.
607  *
608  * @param cls unused
609  * @param client who sent the message
610  * @param message the message received
611  */
612 static void
613 handle_rename_message (void *cls, struct GNUNET_SERVER_Client *client,
614                        const struct GNUNET_MessageHeader *message)
615 {
616   const struct GNUNET_IDENTITY_RenameMessage *rm;
617   uint16_t size;
618   uint16_t old_name_len;
619   uint16_t new_name_len;
620   struct Ego *ego;
621   const char *old_name;
622   const char *new_name;
623   struct RenameContext rename_ctx;
624   char *fn_old;
625   char *fn_new;
626
627   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
628               "Received RENAME message from client\n");
629   size = ntohs (message->size);
630   if (size <= sizeof (struct GNUNET_IDENTITY_RenameMessage))
631   {
632     GNUNET_break (0);
633     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
634     return;
635   }
636   rm = (const struct GNUNET_IDENTITY_RenameMessage *) message;
637   old_name_len = ntohs (rm->old_name_len);
638   new_name_len = ntohs (rm->new_name_len);
639   old_name = (const char *) &rm[1];
640   new_name = &old_name[old_name_len];
641   if ( (old_name_len + new_name_len + sizeof (struct GNUNET_IDENTITY_RenameMessage) != size) ||
642        ('\0' != old_name[old_name_len - 1]) ||
643        ('\0' != new_name[new_name_len - 1]) )
644   {
645     GNUNET_break (0);
646     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
647     return;
648   }
649
650   /* check if new name is already in use */
651   for (ego = ego_head; NULL != ego; ego = ego->next)
652   {
653     if (0 == strcmp (ego->identifier,
654                      new_name))
655     {
656       send_result_code (client, 1, gettext_noop ("target name already exists"));
657       GNUNET_SERVER_receive_done (client, GNUNET_OK);      
658       return;
659     }
660   }
661
662   /* locate old name and, if found, perform rename */
663   for (ego = ego_head; NULL != ego; ego = ego->next)
664   {
665     if (0 == strcmp (ego->identifier,
666                      old_name))
667     {
668       fn_old = get_ego_filename (ego);
669       GNUNET_free (ego->identifier);
670       rename_ctx.old_name = old_name;
671       rename_ctx.new_name = new_name;
672       GNUNET_CONFIGURATION_iterate_sections (subsystem_cfg,
673                                              &handle_ego_rename,
674                                              &rename_ctx);
675       if (GNUNET_OK != 
676           GNUNET_CONFIGURATION_write (subsystem_cfg,
677                                       subsystem_cfg_file))
678         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
679                     _("Failed to write subsystem default identifier map to `%s'.\n"),
680                     subsystem_cfg_file);
681       ego->identifier = GNUNET_strdup (new_name);
682       fn_new = get_ego_filename (ego);      
683       if (0 != RENAME (fn_old, fn_new))
684         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rename", fn_old);
685       GNUNET_free (fn_old);
686       GNUNET_free (fn_new);
687       notify_listeners (ego);
688       send_result_code (client, 0, NULL);
689       GNUNET_SERVER_receive_done (client, GNUNET_OK);
690       return;
691     }
692   }
693
694   /* failed to locate old name */
695   send_result_code (client, 1, gettext_noop ("no matching ego found"));
696   GNUNET_SERVER_receive_done (client, GNUNET_OK);
697 }
698
699
700 /**
701  * An ego was removed, remove it from all subsystems where it is
702  * currently set as the default.
703  *
704  * @param cls name of the removed ego (const char *)
705  * @param section a section in the configuration to process
706  */
707 static void
708 handle_ego_delete (void *cls,
709                    const char *section)
710 {
711   const char *identifier = cls;
712   char *id;
713
714   if (GNUNET_OK !=
715       GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
716                                              section,
717                                              "DEFAULT_IDENTIFIER",
718                                              &id))
719     return;
720   if (0 != strcmp (id, identifier))
721   {
722     GNUNET_free (id);  
723     return;
724   }
725   GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
726                                          section,
727                                          "DEFAULT_IDENTIFIER",
728                                          NULL);
729   GNUNET_free (id);  
730 }
731
732
733 /**
734  * Handler for DELETE message from client, creates
735  * new identity.
736  *
737  * @param cls unused
738  * @param client who sent the message
739  * @param message the message received
740  */
741 static void
742 handle_delete_message (void *cls, struct GNUNET_SERVER_Client *client,
743                        const struct GNUNET_MessageHeader *message)
744 {
745   const struct GNUNET_IDENTITY_DeleteMessage *dm;
746   uint16_t size;
747   uint16_t name_len;
748   struct Ego *ego;
749   const char *name;
750   char *fn;
751
752   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
753               "Received DELETE message from client\n");
754   size = ntohs (message->size);
755   if (size <= sizeof (struct GNUNET_IDENTITY_DeleteMessage))
756   {
757     GNUNET_break (0);
758     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
759     return;
760   }
761   dm = (const struct GNUNET_IDENTITY_DeleteMessage *) message;
762   name = (const char *) &dm[1];
763   name_len = ntohs (dm->name_len);
764   if ( (name_len + sizeof (struct GNUNET_IDENTITY_DeleteMessage) != size) ||
765        (0 != ntohs (dm->reserved)) ||
766        ('\0' != name[name_len - 1]) )
767   {
768     GNUNET_break (0);
769     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
770     return;
771   }
772   for (ego = ego_head; NULL != ego; ego = ego->next)
773   {
774     if (0 == strcmp (ego->identifier,
775                      name))
776     {
777       GNUNET_CONTAINER_DLL_remove (ego_head,
778                                    ego_tail,
779                                    ego);
780       GNUNET_CONFIGURATION_iterate_sections (subsystem_cfg,
781                                              &handle_ego_delete,
782                                              ego->identifier);
783       if (GNUNET_OK != 
784           GNUNET_CONFIGURATION_write (subsystem_cfg,
785                                       subsystem_cfg_file))
786         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
787                     _("Failed to write subsystem default identifier map to `%s'.\n"),
788                     subsystem_cfg_file);
789       fn = get_ego_filename (ego);
790       if (0 != UNLINK (fn))
791         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
792       GNUNET_free (fn);
793       GNUNET_free (ego->identifier);
794       ego->identifier = NULL;
795       notify_listeners (ego);
796       GNUNET_CRYPTO_ecc_key_free (ego->pk);
797       GNUNET_free (ego);
798       send_result_code (client, 0, NULL);
799       GNUNET_SERVER_receive_done (client, GNUNET_OK);
800       return;
801     }
802   }
803
804   send_result_code (client, 1, gettext_noop ("no matching ego found"));
805   GNUNET_SERVER_receive_done (client, GNUNET_OK);
806 }
807
808
809 /**
810  * Process the given file from the "EGODIR".  Parses the file
811  * and creates the respective 'struct Ego' in memory.
812  *
813  * @param cls NULL
814  * @param filename name of the file to parse
815  * @return GNUNET_OK to continue to iterate,
816  *  GNUNET_NO to stop iteration with no error,
817  *  GNUNET_SYSERR to abort iteration with error!
818  */
819 static int
820 process_ego_file (void *cls,
821                   const char *filename)
822 {
823   struct Ego *ego;
824   const char *fn;
825
826   fn = strrchr (filename, (int) DIR_SEPARATOR);
827   if (NULL == fn)
828   {
829     GNUNET_break (0);
830     return GNUNET_OK;
831   }
832   ego = GNUNET_new (struct Ego);
833   ego->pk = GNUNET_CRYPTO_ecc_key_create_from_file (filename);
834   if (NULL == ego->pk)
835     {
836       GNUNET_free (ego);
837       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
838                   _("Failed to parse ego information in `%s'\n"),
839                   filename);
840       return GNUNET_OK;
841     }
842   
843   ego->identifier = GNUNET_strdup (fn);
844   GNUNET_CONTAINER_DLL_insert (ego_head,
845                                ego_tail,
846                                ego);
847   return GNUNET_OK;
848 }
849
850
851 /**
852  * Handle network size estimate clients.
853  *
854  * @param cls closure
855  * @param server the initialized server
856  * @param c configuration to use
857  */
858 static void
859 run (void *cls, 
860      struct GNUNET_SERVER_Handle *server,
861      const struct GNUNET_CONFIGURATION_Handle *c)
862 {
863   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
864     {&handle_start_message, NULL,
865      GNUNET_MESSAGE_TYPE_IDENTITY_START, sizeof (struct GNUNET_MessageHeader)},
866     {&handle_get_default_message, NULL,
867      GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT, 0},
868     {&handle_set_default_message, NULL,
869      GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT, 0},
870     {&handle_create_message, NULL,
871      GNUNET_MESSAGE_TYPE_IDENTITY_CREATE, 0},
872     {&handle_rename_message, NULL,
873      GNUNET_MESSAGE_TYPE_IDENTITY_RENAME, 0},
874     {&handle_delete_message, NULL,
875      GNUNET_MESSAGE_TYPE_IDENTITY_DELETE, 0},
876     {NULL, NULL, 0, 0}
877   };
878
879   cfg = c;
880   if (GNUNET_OK !=
881       GNUNET_CONFIGURATION_get_value_filename (cfg, "identity",
882                                                "EGODIR",
883                                                &ego_directory))
884   {
885     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "EGODIR");
886     GNUNET_SCHEDULER_shutdown ();
887     return;
888   }
889   if (GNUNET_OK !=
890       GNUNET_CONFIGURATION_get_value_filename (cfg, "identity",
891                                                "SUBSYSTEM_CFG",
892                                                &subsystem_cfg_file))
893   {
894     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "SUBSYSTEM_CFG");
895     GNUNET_SCHEDULER_shutdown ();
896     return;
897   }
898   subsystem_cfg = GNUNET_CONFIGURATION_create ();
899   if ( (GNUNET_YES ==
900         GNUNET_DISK_file_test (subsystem_cfg_file)) &&
901        (GNUNET_OK != 
902         GNUNET_CONFIGURATION_parse (subsystem_cfg,
903                                     subsystem_cfg_file)) )
904   {
905     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
906                 _("Failed to parse subsystem identity configuration file `%s'\n"),
907                 subsystem_cfg_file);
908     GNUNET_SCHEDULER_shutdown ();
909     return;
910   }
911   stats = GNUNET_STATISTICS_create ("identity", cfg);
912   GNUNET_SERVER_add_handlers (server, handlers);
913   nc = GNUNET_SERVER_notification_context_create (server, 1);
914   GNUNET_DISK_directory_scan (ego_directory,
915                               &process_ego_file,
916                               NULL);
917   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
918                                 NULL);
919 }
920
921
922 /**
923  * The main function for the network size estimation service.
924  *
925  * @param argc number of arguments from the command line
926  * @param argv command line arguments
927  * @return 0 ok, 1 on error
928  */
929 int
930 main (int argc, char *const *argv)
931 {
932   return (GNUNET_OK ==
933           GNUNET_SERVICE_run (argc, argv, "identity", 
934                               GNUNET_SERVICE_OPTION_NONE,
935                               &run, NULL)) ? 0 : 1;
936 }
937
938
939 /* end of gnunet-service-identity.c */