-towards handling identifier creation
[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  * Task run during shutdown.
111  *
112  * @param cls unused
113  * @param tc unused
114  */
115 static void
116 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
117 {
118   struct Ego *e;
119
120   if (NULL != nc)
121   {
122     GNUNET_SERVER_notification_context_destroy (nc);
123     nc = NULL;
124   }
125   if (NULL != stats)
126   {
127     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
128     stats = NULL;
129   }
130   GNUNET_CONFIGURATION_destroy (subsystem_cfg);
131   subsystem_cfg = NULL;
132   GNUNET_free (subsystem_cfg_file);
133   subsystem_cfg_file = NULL;
134   GNUNET_free (ego_directory);
135   ego_directory = NULL;
136   while (NULL != (e = ego_head))
137   {
138     GNUNET_CONTAINER_DLL_remove (ego_head, ego_tail, e);
139     GNUNET_CRYPTO_ecc_key_free (e->pk);
140     GNUNET_free (e);
141   }
142 }
143
144
145 /**
146  * Send a result code back to the client.
147  *
148  * @param client client that should receive the result code
149  * @param result_code code to transmit
150  * @param emsg error message to include (or NULL for none)
151  */
152 static void
153 send_result_code (struct GNUNET_SERVER_Client *client,
154                   uint32_t result_code,
155                   const char *emsg)
156 {
157   struct GNUNET_IDENTITY_ResultCodeMessage *rcm;
158   size_t elen;
159
160   if (NULL == emsg)
161     elen = 0;
162   else
163     elen = strlen (emsg) + 1;
164   rcm = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) + elen);
165   rcm->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE);
166   rcm->header.size = htons (sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) + elen);
167   rcm->result_code = htonl (result_code);
168   memcpy (&rcm[1], emsg, elen);
169   GNUNET_SERVER_notification_context_unicast (nc, client, &rcm->header, GNUNET_YES);  
170   GNUNET_free (rcm);
171 }
172
173
174 /**
175  * Create an update message with information about the current state of an ego.
176  *
177  * @param ego ego to create message for
178  * @return corresponding update message
179  */
180 static struct GNUNET_IDENTITY_UpdateMessage *
181 create_update_message (struct Ego *ego)
182 {
183   struct GNUNET_IDENTITY_UpdateMessage *um;
184   char *str;
185   uint16_t pk_len;
186   size_t name_len;
187   struct GNUNET_CRYPTO_EccPrivateKeyBinaryEncoded *enc;
188
189   name_len = (NULL == ego->identifier) ? 0 : (strlen (ego->identifier) + 1);
190   enc = GNUNET_CRYPTO_ecc_encode_key (ego->pk);
191   pk_len = ntohs (enc->size);
192   um = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_UpdateMessage) + pk_len + name_len);
193   um->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
194   um->header.size = htons (sizeof (struct GNUNET_IDENTITY_UpdateMessage) + pk_len + name_len);
195   um->name_len = htons (name_len);
196   um->pk_len = htons (pk_len);
197   str = (char *) &um[1];
198   memcpy (str, enc, pk_len);
199   memcpy (&str[pk_len], ego->identifier, name_len);
200   GNUNET_free (enc);
201   return um;
202 }
203
204
205 /**
206  * Handler for START message from client, sends information
207  * about all identities to the client immediately and 
208  * adds the client to the notification context for future
209  * updates.
210  *
211  * @param cls unused
212  * @param client who sent the message
213  * @param message the message received
214  */
215 static void
216 handle_start_message (void *cls, struct GNUNET_SERVER_Client *client,
217                       const struct GNUNET_MessageHeader *message)
218 {
219   struct GNUNET_IDENTITY_UpdateMessage *um;
220   struct Ego *ego;
221
222   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
223               "Received START message from client\n");
224   GNUNET_SERVER_notification_context_add (nc, client);
225   for (ego = ego_head; NULL != ego; ego = ego->next)
226   {
227     um = create_update_message (ego);
228     GNUNET_SERVER_notification_context_unicast (nc, client, &um->header, GNUNET_YES);
229     GNUNET_free (um);
230   }
231   GNUNET_SERVER_receive_done (client, GNUNET_OK);
232 }
233
234
235 /**
236  * Handler for GET_DEFAULT message from client, returns
237  * default identity for some service.
238  *
239  * @param cls unused
240  * @param client who sent the message
241  * @param message the message received
242  */
243 static void
244 handle_get_default_message (void *cls, struct GNUNET_SERVER_Client *client,
245                             const struct GNUNET_MessageHeader *message)
246 {
247   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
248               "Received GET_DEFAULT message from client\n");
249   // setup_estimate_message (&em);
250   // GNUNET_SERVER_notification_context_unicast (nc, client, &em.header, GNUNET_YES);
251   GNUNET_break (0); // not implemented!
252   GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
253 }
254
255
256 /**
257  * Handler for SET_DEFAULT message from client, updates
258  * default identity for some service.
259  *
260  * @param cls unused
261  * @param client who sent the message
262  * @param message the message received
263  */
264 static void
265 handle_set_default_message (void *cls, struct GNUNET_SERVER_Client *client,
266                             const struct GNUNET_MessageHeader *message)
267 {
268   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
269               "Received SET_DEFAULT message from client\n");
270   // setup_estimate_message (&em);
271   // GNUNET_SERVER_notification_context_unicast (nc, client, &em.header, GNUNET_YES);
272   GNUNET_break (0); // not implemented!
273   GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
274 }
275
276
277 /**
278  * Send an updated message for the given ego to all listeners.
279  *
280  * @param ego ego to send the update for
281  */
282 static void
283 notify_listeners (struct Ego *ego)
284 {
285   struct GNUNET_IDENTITY_UpdateMessage *um;
286
287   um = create_update_message (ego);
288   GNUNET_SERVER_notification_context_broadcast (nc, &um->header, GNUNET_YES);
289   GNUNET_free (um);
290 }
291
292
293 /**
294  * Handler for CREATE message from client, creates
295  * new identity.
296  *
297  * @param cls unused
298  * @param client who sent the message
299  * @param message the message received
300  */
301 static void
302 handle_create_message (void *cls, struct GNUNET_SERVER_Client *client,
303                        const struct GNUNET_MessageHeader *message)
304 {
305   const struct GNUNET_IDENTITY_CreateRequestMessage *crm;
306   uint16_t size;
307   uint16_t name_len;
308   uint16_t pk_len;
309   struct Ego *ego;
310   const char *str;
311   struct GNUNET_CRYPTO_EccPrivateKey *pk;
312
313   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
314               "Received CREATE message from client\n");
315   size = ntohs (message->size);
316   if (size <= sizeof (struct GNUNET_IDENTITY_CreateRequestMessage))
317   {
318     GNUNET_break (0);
319     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
320     return;
321   }
322   crm = (const struct GNUNET_IDENTITY_CreateRequestMessage *) message;
323   name_len = ntohs (crm->name_len);
324   pk_len = ntohs (crm->pk_len);
325   str = (const char *) &crm[1];
326   if ( (name_len + pk_len + sizeof (struct GNUNET_IDENTITY_CreateRequestMessage) != size) ||
327        (NULL == (pk = GNUNET_CRYPTO_ecc_decode_key (str, pk_len, GNUNET_YES))) )
328   {
329     GNUNET_break (0);
330     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
331     return;
332   }
333   str = &str[pk_len];
334   if ('\0' != str[name_len - 1])
335   {
336     GNUNET_break (0);
337     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
338     return;
339   }
340   for (ego = ego_head; NULL != ego; ego = ego->next)
341   {
342     if (0 == strcmp (ego->identifier,
343                      str))
344     {
345       send_result_code (client, 1, gettext_noop ("identifier already in use for another ego"));
346       GNUNET_SERVER_receive_done (client, GNUNET_OK);
347       GNUNET_CRYPTO_ecc_key_free (pk);
348       return;
349     }
350   }
351   ego = GNUNET_new (struct Ego);
352   ego->pk = pk;
353   ego->identifier = GNUNET_strdup (str);
354   GNUNET_CONTAINER_DLL_insert (ego_head,
355                                ego_tail,
356                                ego);
357   send_result_code (client, 0, NULL);
358   /* FIXME: also write to file! */
359   notify_listeners (ego);  
360   GNUNET_SERVER_receive_done (client, GNUNET_OK);
361 }
362
363
364
365 /**
366  * Handler for RENAME message from client, creates
367  * new identity.
368  *
369  * @param cls unused
370  * @param client who sent the message
371  * @param message the message received
372  */
373 static void
374 handle_rename_message (void *cls, struct GNUNET_SERVER_Client *client,
375                        const struct GNUNET_MessageHeader *message)
376 {
377   const struct GNUNET_IDENTITY_RenameMessage *rm;
378   uint16_t size;
379   uint16_t old_name_len;
380   uint16_t new_name_len;
381   struct Ego *ego;
382   const char *old_name;
383   const char *new_name;
384
385   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
386               "Received RENAME message from client\n");
387   size = ntohs (message->size);
388   if (size <= sizeof (struct GNUNET_IDENTITY_RenameMessage))
389   {
390     GNUNET_break (0);
391     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
392     return;
393   }
394   rm = (const struct GNUNET_IDENTITY_RenameMessage *) message;
395   old_name_len = ntohs (rm->old_name_len);
396   new_name_len = ntohs (rm->new_name_len);
397   old_name = (const char *) &rm[1];
398   new_name = &old_name[old_name_len];
399   if ( (old_name_len + new_name_len + sizeof (struct GNUNET_IDENTITY_RenameMessage) != size) ||
400        ('\0' != old_name[old_name_len - 1]) ||
401        ('\0' != new_name[new_name_len - 1]) )
402   {
403     GNUNET_break (0);
404     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
405     return;
406   }
407   for (ego = ego_head; NULL != ego; ego = ego->next)
408   {
409     if (0 == strcmp (ego->identifier,
410                      old_name))
411     {
412       GNUNET_free (ego->identifier);
413       ego->identifier = GNUNET_strdup (new_name);
414       /* FIXME: also rename file! */
415       notify_listeners (ego);
416       send_result_code (client, 0, NULL);
417       GNUNET_SERVER_receive_done (client, GNUNET_OK);
418       return;
419     }
420   }
421
422   send_result_code (client, 1, gettext_noop ("no matching ego found"));
423   GNUNET_SERVER_receive_done (client, GNUNET_OK);
424 }
425
426
427 /**
428  * Handler for DELETE message from client, creates
429  * new identity.
430  *
431  * @param cls unused
432  * @param client who sent the message
433  * @param message the message received
434  */
435 static void
436 handle_delete_message (void *cls, struct GNUNET_SERVER_Client *client,
437                        const struct GNUNET_MessageHeader *message)
438 {
439   const struct GNUNET_IDENTITY_DeleteMessage *dm;
440   uint16_t size;
441   uint16_t name_len;
442   struct Ego *ego;
443   const char *name;
444
445   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
446               "Received DELETE message from client\n");
447   size = ntohs (message->size);
448   if (size <= sizeof (struct GNUNET_IDENTITY_DeleteMessage))
449   {
450     GNUNET_break (0);
451     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
452     return;
453   }
454   dm = (const struct GNUNET_IDENTITY_DeleteMessage *) message;
455   name = (const char *) &dm[1];
456   name_len = ntohs (dm->name_len);
457   if ( (name_len + sizeof (struct GNUNET_IDENTITY_DeleteMessage) != size) ||
458        (0 != ntohs (dm->reserved)) ||
459        ('\0' != name[name_len - 1]) )
460   {
461     GNUNET_break (0);
462     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
463     return;
464   }
465   for (ego = ego_head; NULL != ego; ego = ego->next)
466   {
467     if (0 == strcmp (ego->identifier,
468                      name))
469     {
470       GNUNET_CONTAINER_DLL_remove (ego_head,
471                                    ego_tail,
472                                    ego);
473       /* FIXME: also delete file! */
474       GNUNET_free (ego->identifier);
475       ego->identifier = NULL;
476       notify_listeners (ego);
477       GNUNET_CRYPTO_ecc_key_free (ego->pk);
478       GNUNET_free (ego);
479       send_result_code (client, 0, NULL);
480       GNUNET_SERVER_receive_done (client, GNUNET_OK);
481       return;
482     }
483   }
484
485   send_result_code (client, 1, gettext_noop ("no matching ego found"));
486   GNUNET_SERVER_receive_done (client, GNUNET_OK);
487 }
488
489
490 /**
491  * Handle network size estimate clients.
492  *
493  * @param cls closure
494  * @param server the initialized server
495  * @param c configuration to use
496  */
497 static void
498 run (void *cls, 
499      struct GNUNET_SERVER_Handle *server,
500      const struct GNUNET_CONFIGURATION_Handle *c)
501 {
502   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
503     {&handle_start_message, NULL,
504      GNUNET_MESSAGE_TYPE_IDENTITY_START, sizeof (struct GNUNET_MessageHeader)},
505     {&handle_get_default_message, NULL,
506      GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT, 0},
507     {&handle_set_default_message, NULL,
508      GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT, 0},
509     {&handle_create_message, NULL,
510      GNUNET_MESSAGE_TYPE_IDENTITY_CREATE, 0},
511     {&handle_rename_message, NULL,
512      GNUNET_MESSAGE_TYPE_IDENTITY_RENAME, 0},
513     {&handle_delete_message, NULL,
514      GNUNET_MESSAGE_TYPE_IDENTITY_DELETE, 0},
515     {NULL, NULL, 0, 0}
516   };
517
518   cfg = c;
519   if (GNUNET_OK !=
520       GNUNET_CONFIGURATION_get_value_filename (cfg, "identity",
521                                                "EGODIR",
522                                                &ego_directory))
523   {
524     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "EGODIR");
525     GNUNET_SCHEDULER_shutdown ();
526     return;
527   }
528   if (GNUNET_OK !=
529       GNUNET_CONFIGURATION_get_value_filename (cfg, "identity",
530                                                "SUBSYSTEM_CFG",
531                                                &subsystem_cfg_file))
532   {
533     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "SUBSYSTEM_CFG");
534     GNUNET_SCHEDULER_shutdown ();
535     return;
536   }
537   subsystem_cfg = GNUNET_CONFIGURATION_create ();
538   if ( (GNUNET_YES ==
539         GNUNET_DISK_file_test (subsystem_cfg_file)) &&
540        (GNUNET_OK != 
541         GNUNET_CONFIGURATION_parse (subsystem_cfg,
542                                     subsystem_cfg_file)) )
543   {
544     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
545                 _("Failed to parse subsystem identity configuration file `%s'\n"),
546                 subsystem_cfg_file);
547     GNUNET_SCHEDULER_shutdown ();
548     return;
549   }
550   stats = GNUNET_STATISTICS_create ("identity", cfg);
551   GNUNET_SERVER_add_handlers (server, handlers);
552   nc = GNUNET_SERVER_notification_context_create (server, 1);
553   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
554                                 NULL);
555 }
556
557
558 /**
559  * The main function for the network size estimation service.
560  *
561  * @param argc number of arguments from the command line
562  * @param argv command line arguments
563  * @return 0 ok, 1 on error
564  */
565 int
566 main (int argc, char *const *argv)
567 {
568   return (GNUNET_OK ==
569           GNUNET_SERVICE_run (argc, argv, "identity", 
570                               GNUNET_SERVICE_OPTION_NONE,
571                               &run, NULL)) ? 0 : 1;
572 }
573
574
575 /* end of gnunet-service-identity.c */