6a2686dd4db93b799b5b0aa34578e4ad88f78662
[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   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
306               "Received CREATE message from client\n");
307   // setup_estimate_message (&em);
308   // GNUNET_SERVER_notification_context_unicast (nc, client, &em.header, GNUNET_YES);
309   GNUNET_break (0); // not implemented!
310   GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
311 }
312
313
314
315 /**
316  * Handler for RENAME message from client, creates
317  * new identity.
318  *
319  * @param cls unused
320  * @param client who sent the message
321  * @param message the message received
322  */
323 static void
324 handle_rename_message (void *cls, struct GNUNET_SERVER_Client *client,
325                        const struct GNUNET_MessageHeader *message)
326 {
327   const struct GNUNET_IDENTITY_RenameMessage *rm;
328   uint16_t size;
329   uint16_t old_name_len;
330   uint16_t new_name_len;
331   struct Ego *ego;
332   const char *old_name;
333   const char *new_name;
334
335   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
336               "Received RENAME message from client\n");
337   size = ntohs (message->size);
338   if (size <= sizeof (struct GNUNET_IDENTITY_RenameMessage))
339   {
340     GNUNET_break (0);
341     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
342     return;
343   }
344   rm = (const struct GNUNET_IDENTITY_RenameMessage *) message;
345   old_name_len = ntohs (rm->old_name_len);
346   new_name_len = ntohs (rm->new_name_len);
347   old_name = (const char *) &rm[1];
348   new_name = &old_name[old_name_len];
349   if ( (old_name_len + new_name_len + sizeof (struct GNUNET_IDENTITY_RenameMessage) != size) ||
350        ('\0' != old_name[old_name_len - 1]) ||
351        ('\0' != new_name[new_name_len - 1]) )
352   {
353     GNUNET_break (0);
354     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
355     return;
356   }
357   for (ego = ego_head; NULL != ego; ego = ego->next)
358   {
359     if (0 == strcmp (ego->identifier,
360                      old_name))
361     {
362       GNUNET_free (ego->identifier);
363       ego->identifier = GNUNET_strdup (new_name);
364       /* FIXME: also rename file! */
365       notify_listeners (ego);
366       send_result_code (client, 0, NULL);
367       GNUNET_SERVER_receive_done (client, GNUNET_OK);
368       return;
369     }
370   }
371
372   send_result_code (client, 1, gettext_noop ("no matching ego found"));
373   GNUNET_SERVER_receive_done (client, GNUNET_OK);
374 }
375
376
377 /**
378  * Handler for DELETE message from client, creates
379  * new identity.
380  *
381  * @param cls unused
382  * @param client who sent the message
383  * @param message the message received
384  */
385 static void
386 handle_delete_message (void *cls, struct GNUNET_SERVER_Client *client,
387                        const struct GNUNET_MessageHeader *message)
388 {
389   const struct GNUNET_IDENTITY_DeleteMessage *dm;
390   uint16_t size;
391   uint16_t name_len;
392   struct Ego *ego;
393   const char *name;
394
395   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
396               "Received DELETE message from client\n");
397   size = ntohs (message->size);
398   if (size <= sizeof (struct GNUNET_IDENTITY_DeleteMessage))
399   {
400     GNUNET_break (0);
401     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
402     return;
403   }
404   dm = (const struct GNUNET_IDENTITY_DeleteMessage *) message;
405   name = (const char *) &dm[1];
406   name_len = ntohs (dm->name_len);
407   if ( (name_len + sizeof (struct GNUNET_IDENTITY_DeleteMessage) != size) ||
408        (0 != ntohs (dm->reserved)) ||
409        ('\0' != name[name_len - 1]) )
410   {
411     GNUNET_break (0);
412     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
413     return;
414   }
415   for (ego = ego_head; NULL != ego; ego = ego->next)
416   {
417     if (0 == strcmp (ego->identifier,
418                      name))
419     {
420       GNUNET_CONTAINER_DLL_remove (ego_head,
421                                    ego_tail,
422                                    ego);
423       /* FIXME: also delete file! */
424       GNUNET_free (ego->identifier);
425       ego->identifier = NULL;
426       notify_listeners (ego);
427       GNUNET_CRYPTO_ecc_key_free (ego->pk);
428       GNUNET_free (ego);
429       send_result_code (client, 0, NULL);
430       GNUNET_SERVER_receive_done (client, GNUNET_OK);
431       return;
432     }
433   }
434
435   send_result_code (client, 1, gettext_noop ("no matching ego found"));
436   GNUNET_SERVER_receive_done (client, GNUNET_OK);
437 }
438
439
440 /**
441  * Handle network size estimate clients.
442  *
443  * @param cls closure
444  * @param server the initialized server
445  * @param c configuration to use
446  */
447 static void
448 run (void *cls, 
449      struct GNUNET_SERVER_Handle *server,
450      const struct GNUNET_CONFIGURATION_Handle *c)
451 {
452   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
453     {&handle_start_message, NULL,
454      GNUNET_MESSAGE_TYPE_IDENTITY_START, sizeof (struct GNUNET_MessageHeader)},
455     {&handle_get_default_message, NULL,
456      GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT, 0},
457     {&handle_set_default_message, NULL,
458      GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT, 0},
459     {&handle_create_message, NULL,
460      GNUNET_MESSAGE_TYPE_IDENTITY_CREATE, 0},
461     {&handle_rename_message, NULL,
462      GNUNET_MESSAGE_TYPE_IDENTITY_RENAME, 0},
463     {&handle_delete_message, NULL,
464      GNUNET_MESSAGE_TYPE_IDENTITY_DELETE, 0},
465     {NULL, NULL, 0, 0}
466   };
467
468   cfg = c;
469   if (GNUNET_OK !=
470       GNUNET_CONFIGURATION_get_value_filename (cfg, "identity",
471                                                "EGODIR",
472                                                &ego_directory))
473   {
474     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "EGODIR");
475     GNUNET_SCHEDULER_shutdown ();
476     return;
477   }
478   if (GNUNET_OK !=
479       GNUNET_CONFIGURATION_get_value_filename (cfg, "identity",
480                                                "SUBSYSTEM_CFG",
481                                                &subsystem_cfg_file))
482   {
483     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "SUBSYSTEM_CFG");
484     GNUNET_SCHEDULER_shutdown ();
485     return;
486   }
487   subsystem_cfg = GNUNET_CONFIGURATION_create ();
488   if ( (GNUNET_YES ==
489         GNUNET_DISK_file_test (subsystem_cfg_file)) &&
490        (GNUNET_OK != 
491         GNUNET_CONFIGURATION_parse (subsystem_cfg,
492                                     subsystem_cfg_file)) )
493   {
494     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
495                 _("Failed to parse subsystem identity configuration file `%s'\n"),
496                 subsystem_cfg_file);
497     GNUNET_SCHEDULER_shutdown ();
498     return;
499   }
500   stats = GNUNET_STATISTICS_create ("identity", cfg);
501   GNUNET_SERVER_add_handlers (server, handlers);
502   nc = GNUNET_SERVER_notification_context_create (server, 1);
503   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
504                                 NULL);
505 }
506
507
508 /**
509  * The main function for the network size estimation service.
510  *
511  * @param argc number of arguments from the command line
512  * @param argv command line arguments
513  * @return 0 ok, 1 on error
514  */
515 int
516 main (int argc, char *const *argv)
517 {
518   return (GNUNET_OK ==
519           GNUNET_SERVICE_run (argc, argv, "identity", 
520                               GNUNET_SERVICE_OPTION_NONE,
521                               &run, NULL)) ? 0 : 1;
522 }
523
524
525 /* end of gnunet-service-identity.c */