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