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