aboutsummaryrefslogtreecommitdiff
path: root/src/service/identity/gnunet-service-identity.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/identity/gnunet-service-identity.c')
-rw-r--r--src/service/identity/gnunet-service-identity.c1035
1 files changed, 1035 insertions, 0 deletions
diff --git a/src/service/identity/gnunet-service-identity.c b/src/service/identity/gnunet-service-identity.c
new file mode 100644
index 000000000..7ac4bf2b9
--- /dev/null
+++ b/src/service/identity/gnunet-service-identity.c
@@ -0,0 +1,1035 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
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 */
45struct Ego
46{
47 /**
48 * We keep egos in a DLL.
49 */
50 struct Ego *next;
51
52 /**
53 * We keep egos in a DLL.
54 */
55 struct Ego *prev;
56
57 /**
58 * Private key of the ego.
59 */
60 struct GNUNET_CRYPTO_PrivateKey pk;
61
62 /**
63 * String identifier for the ego.
64 */
65 char *identifier;
66};
67
68
69/**
70 * Handle to our current configuration.
71 */
72static const struct GNUNET_CONFIGURATION_Handle *cfg;
73
74/**
75 * Handle to subsystem configuration which for each subsystem contains
76 * the name of the default ego.
77 */
78static struct GNUNET_CONFIGURATION_Handle *subsystem_cfg;
79
80/**
81 * Handle to the statistics service.
82 */
83static struct GNUNET_STATISTICS_Handle *stats;
84
85/**
86 * Notification context, simplifies client broadcasts.
87 */
88static struct GNUNET_NotificationContext *nc;
89
90/**
91 * Directory where we store the identities.
92 */
93static char *ego_directory;
94
95/**
96 * Configuration file name where subsystem information is kept.
97 */
98static char *subsystem_cfg_file;
99
100/**
101 * Head of DLL of all egos.
102 */
103static struct Ego *ego_head;
104
105/**
106 * Tail of DLL of all egos.
107 */
108static struct Ego *ego_tail;
109
110
111/**
112 * Get the name of the file we use to store a given ego.
113 *
114 * @param ego ego for which we need the filename
115 * @return full filename for the given ego
116 */
117static char *
118get_ego_filename (struct Ego *ego)
119{
120 char *filename;
121
122 GNUNET_asprintf (&filename,
123 "%s%s%s",
124 ego_directory,
125 DIR_SEPARATOR_STR,
126 ego->identifier);
127 return filename;
128}
129
130
131/**
132 * Called whenever a client is disconnected.
133 *
134 * @param cls closure
135 * @param client identification of the client
136 * @param app_ctx @a client
137 */
138static void
139client_disconnect_cb (void *cls,
140 struct GNUNET_SERVICE_Client *client,
141 void *app_ctx)
142{
143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
144 "Client %p disconnected\n",
145 client);
146}
147
148
149/**
150 * Add a client to our list of active clients.
151 *
152 * @param cls NULL
153 * @param client client to add
154 * @param mq message queue for @a client
155 * @return internal namestore client structure for this client
156 */
157static void *
158client_connect_cb (void *cls,
159 struct GNUNET_SERVICE_Client *client,
160 struct GNUNET_MQ_Handle *mq)
161{
162 return client;
163}
164
165
166/**
167 * Task run during shutdown.
168 *
169 * @param cls unused
170 */
171static void
172shutdown_task (void *cls)
173{
174 struct Ego *e;
175
176 if (NULL != nc)
177 {
178 GNUNET_notification_context_destroy (nc);
179 nc = NULL;
180 }
181 if (NULL != stats)
182 {
183 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
184 stats = NULL;
185 }
186 GNUNET_CONFIGURATION_destroy (subsystem_cfg);
187 subsystem_cfg = NULL;
188 GNUNET_free (subsystem_cfg_file);
189 subsystem_cfg_file = NULL;
190 GNUNET_free (ego_directory);
191 ego_directory = NULL;
192 while (NULL != (e = ego_head))
193 {
194 GNUNET_CONTAINER_DLL_remove (ego_head,
195 ego_tail,
196 e);
197 GNUNET_free (e->identifier);
198 GNUNET_free (e);
199 }
200}
201
202
203/**
204 * Send a result code back to the client.
205 *
206 * @param client client that should receive the result code
207 * @param result_code code to transmit
208 */
209static void
210send_result_code (struct GNUNET_SERVICE_Client *client,
211 uint32_t result_code)
212{
213 struct ResultCodeMessage *rcm;
214 struct GNUNET_MQ_Envelope *env;
215
216 env =
217 GNUNET_MQ_msg (rcm, GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE);
218 rcm->result_code = htonl (result_code);
219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
220 "Sending result %d (%s) to client\n",
221 (int) result_code,
222 GNUNET_ErrorCode_get_hint (result_code));
223 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
224}
225
226
227/**
228 * Create an update message with information about the current state of an ego.
229 *
230 * @param ego ego to create message for
231 * @return corresponding update message
232 */
233static struct GNUNET_MQ_Envelope *
234create_update_message (struct Ego *ego)
235{
236 struct UpdateMessage *um;
237 struct GNUNET_MQ_Envelope *env;
238 size_t name_len;
239 ssize_t key_len;
240
241 key_len = GNUNET_CRYPTO_private_key_get_length (&ego->pk);
242 name_len = (NULL == ego->identifier) ? 0 : (strlen (ego->identifier) + 1);
243 env = GNUNET_MQ_msg_extra (um, name_len + key_len,
244 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
245 um->name_len = htons (name_len);
246 um->end_of_list = htons (GNUNET_NO);
247 um->key_len = htons (key_len);
248 GNUNET_memcpy (&um[1], ego->identifier, name_len);
249 GNUNET_CRYPTO_write_private_key_to_buffer (&ego->pk,
250 ((char*) &um[1]) + name_len,
251 key_len);
252 return env;
253}
254
255
256/**
257 * Handler for START message from client, sends information
258 * about all identities to the client immediately and
259 * adds the client to the notification context for future
260 * updates.
261 *
262 * @param cls a `struct GNUNET_SERVICE_Client *`
263 * @param message the message received
264 */
265static void
266handle_start_message (void *cls,
267 const struct GNUNET_MessageHeader *message)
268{
269 struct GNUNET_SERVICE_Client *client = cls;
270
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272 "Received START message from client\n");
273 GNUNET_SERVICE_client_mark_monitor (client);
274 GNUNET_SERVICE_client_disable_continue_warning (client);
275 GNUNET_notification_context_add (nc,
276 GNUNET_SERVICE_client_get_mq (client));
277 for (struct Ego *ego = ego_head; NULL != ego; ego = ego->next)
278 {
279 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
280 create_update_message (ego));
281 }
282 {
283 struct UpdateMessage *ume;
284 struct GNUNET_MQ_Envelope *env;
285
286 env = GNUNET_MQ_msg_extra (ume,
287 0,
288 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
289 ume->end_of_list = htons (GNUNET_YES);
290 ume->name_len = htons (0);
291 ume->key_len = htons (0);
292 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
293 env);
294 }
295 GNUNET_SERVICE_client_continue (client);
296}
297
298
299/**
300 * Handler for LOOKUP message from client, sends information
301 * about ONE identity to the client immediately.
302 *
303 * @param cls unused
304 * @param message the message received
305 * @return #GNUNET_SYSERR if message was ill-formed
306 */
307static int
308check_lookup_message (void *cls,
309 const struct LookupMessage *message)
310{
311 GNUNET_MQ_check_zero_termination (message);
312 return GNUNET_OK;
313}
314
315
316/**
317 * Handler for LOOKUP message from client, sends information
318 * about ONE identity to the client immediately.
319 *
320 * @param cls a `struct GNUNET_SERVICE_Client *`
321 * @param message the message received
322 */
323static void
324handle_lookup_message (void *cls,
325 const struct LookupMessage *message)
326{
327 struct GNUNET_SERVICE_Client *client = cls;
328 const char *name;
329 struct GNUNET_MQ_Envelope *env;
330 struct Ego *ego;
331
332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
333 "Received LOOKUP message from client\n");
334 name = (const char *) &message[1];
335 for (ego = ego_head; NULL != ego; ego = ego->next)
336 {
337 if (0 != strcasecmp (name, ego->identifier))
338 continue;
339 env = create_update_message (ego);
340 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
341 GNUNET_SERVICE_client_continue (client);
342 return;
343 }
344 send_result_code (client, GNUNET_EC_IDENTITY_NOT_FOUND);
345 GNUNET_SERVICE_client_continue (client);
346}
347
348
349/**
350 * Handler for LOOKUP message from client, sends information
351 * about ONE identity to the client immediately.
352 *
353 * @param cls unused
354 * @param message the message received
355 * @return #GNUNET_SYSERR if message was ill-formed
356 */
357static int
358check_lookup_by_suffix_message (void *cls,
359 const struct LookupMessage *message)
360{
361 GNUNET_MQ_check_zero_termination (message);
362 return GNUNET_OK;
363}
364
365
366/**
367 * Handler for LOOKUP_BY_SUFFIX message from client, sends information
368 * about ONE identity to the client immediately.
369 *
370 * @param cls a `struct GNUNET_SERVICE_Client *`
371 * @param message the message received
372 */
373static void
374handle_lookup_by_suffix_message (void *cls,
375 const struct LookupMessage *message)
376{
377 struct GNUNET_SERVICE_Client *client = cls;
378 const char *name;
379 struct GNUNET_MQ_Envelope *env;
380 struct Ego *lprefix;
381
382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
383 "Received LOOKUP_BY_SUFFIX message from client\n");
384 name = (const char *) &message[1];
385 lprefix = NULL;
386 for (struct Ego *ego = ego_head; NULL != ego; ego = ego->next)
387 {
388 if ((strlen (ego->identifier) <= strlen (name)) &&
389 (0 == strcmp (ego->identifier,
390 &name[strlen (name) - strlen (ego->identifier)])) &&
391 ((strlen (name) == strlen (ego->identifier)) ||
392 ('.' == name[strlen (name) - strlen (ego->identifier) - 1])) &&
393 ((NULL == lprefix) ||
394 (strlen (ego->identifier) > strlen (lprefix->identifier))))
395 {
396 /* found better match, update! */
397 lprefix = ego;
398 }
399 }
400 if (NULL != lprefix)
401 {
402 env = create_update_message (lprefix);
403 GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
404 GNUNET_SERVICE_client_continue (client);
405 return;
406 }
407 send_result_code (client, GNUNET_EC_IDENTITY_NOT_FOUND);
408 GNUNET_SERVICE_client_continue (client);
409}
410
411
412/**
413 * Send an updated message for the given ego to all listeners.
414 *
415 * @param ego ego to send the update for
416 */
417static void
418notify_listeners (struct Ego *ego)
419{
420 struct UpdateMessage *um;
421 size_t name_len;
422 ssize_t key_len;
423
424 name_len = (NULL == ego->identifier) ? 0 : (strlen (ego->identifier) + 1);
425 key_len = GNUNET_CRYPTO_private_key_get_length (&ego->pk);
426 um = GNUNET_malloc (sizeof(struct UpdateMessage) + name_len + key_len);
427 um->header.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
428 um->header.size = htons (sizeof(struct UpdateMessage) + name_len + key_len);
429 um->name_len = htons (name_len);
430 um->end_of_list = htons (GNUNET_NO);
431 um->key_len = htons (key_len);
432 GNUNET_memcpy (&um[1], ego->identifier, name_len);
433 GNUNET_CRYPTO_write_private_key_to_buffer (&ego->pk,
434 ((char*) &um[1]) + name_len,
435 key_len);
436 GNUNET_notification_context_broadcast (nc, &um->header, GNUNET_NO);
437 GNUNET_free (um);
438}
439
440
441/**
442 * Checks a #GNUNET_MESSAGE_TYPE_IDENTITY_CREATE message
443 *
444 * @param cls client sending the message
445 * @param msg message of type `struct CreateRequestMessage`
446 * @return #GNUNET_OK if @a msg is well-formed
447 */
448static int
449check_create_message (void *cls,
450 const struct CreateRequestMessage *msg)
451{
452 uint16_t size;
453 uint16_t name_len;
454 size_t key_len;
455 const char *str;
456
457 size = ntohs (msg->header.size);
458 if (size <= sizeof(struct CreateRequestMessage))
459 {
460 GNUNET_break (0);
461 return GNUNET_SYSERR;
462 }
463 name_len = ntohs (msg->name_len);
464 key_len = ntohs (msg->key_len);
465 if (name_len + key_len + sizeof(struct CreateRequestMessage) != size)
466 {
467 GNUNET_break (0);
468 return GNUNET_SYSERR;
469 }
470 str = (const char *) &msg[1] + key_len;
471 if ('\0' != str[name_len - 1])
472 {
473 GNUNET_break (0);
474 return GNUNET_SYSERR;
475 }
476 return GNUNET_OK;
477}
478
479
480/**
481 * Handler for CREATE message from client, creates new identity.
482 *
483 * @param cls unused
484 * @param crm the message received
485 */
486static void
487handle_create_message (void *cls,
488 const struct CreateRequestMessage *crm)
489{
490 struct GNUNET_CRYPTO_PrivateKey private_key;
491 struct GNUNET_SERVICE_Client *client = cls;
492 struct Ego *ego;
493 char *str;
494 char *fn;
495 size_t key_len;
496 size_t kb_read;
497
498 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CREATE message from client\n");
499 key_len = ntohs (crm->key_len);
500 if ((GNUNET_SYSERR ==
501 GNUNET_CRYPTO_read_private_key_from_buffer (&crm[1],
502 key_len,
503 &private_key,
504 &kb_read)) ||
505 (kb_read != key_len))
506 {
507 GNUNET_SERVICE_client_drop (client);
508 return;
509 }
510 str = GNUNET_strdup ((const char *) &crm[1] + key_len);
511 GNUNET_STRINGS_utf8_tolower ((const char *) &crm[1] + key_len, str);
512 for (ego = ego_head; NULL != ego; ego = ego->next)
513 {
514 if (0 == strcmp (ego->identifier, str))
515 {
516 send_result_code (client,
517 GNUNET_EC_IDENTITY_NAME_CONFLICT);
518 GNUNET_SERVICE_client_continue (client);
519 GNUNET_free (str);
520 return;
521 }
522 }
523 ego = GNUNET_new (struct Ego);
524 ego->pk = private_key;
525 ego->identifier = GNUNET_strdup (str);
526 GNUNET_CONTAINER_DLL_insert (ego_head,
527 ego_tail,
528 ego);
529 send_result_code (client, GNUNET_EC_NONE);
530 fn = get_ego_filename (ego);
531 if (GNUNET_OK !=
532 GNUNET_DISK_fn_write (fn,
533 &private_key,
534 sizeof(struct GNUNET_CRYPTO_PrivateKey),
535 GNUNET_DISK_PERM_USER_READ
536 | GNUNET_DISK_PERM_USER_WRITE))
537 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "write", fn);
538 GNUNET_free (fn);
539 GNUNET_free (str);
540 notify_listeners (ego);
541 GNUNET_SERVICE_client_continue (client);
542}
543
544
545/**
546 * Closure for 'handle_ego_rename'.
547 */
548struct 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 * An ego was renamed; rename it in all subsystems where it is
563 * currently set as the default.
564 *
565 * @param cls the 'struct RenameContext'
566 * @param section a section in the configuration to process
567 */
568static void
569handle_ego_rename (void *cls, const char *section)
570{
571 struct RenameContext *rc = cls;
572 char *id;
573
574 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
575 section,
576 "DEFAULT_IDENTIFIER",
577 &id))
578 return;
579 if (0 != strcmp (id, rc->old_name))
580 {
581 GNUNET_free (id);
582 return;
583 }
584 GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
585 section,
586 "DEFAULT_IDENTIFIER",
587 rc->new_name);
588 GNUNET_free (id);
589}
590
591
592/**
593 * Checks a #GNUNET_MESSAGE_TYPE_IDENTITY_RENAME message
594 *
595 * @param cls client sending the message
596 * @param msg message of type `struct RenameMessage`
597 * @return #GNUNET_OK if @a msg is well-formed
598 */
599static int
600check_rename_message (void *cls, const struct RenameMessage *msg)
601{
602 uint16_t size;
603 uint16_t old_name_len;
604 uint16_t new_name_len;
605 const char *old_name;
606 const char *new_name;
607
608 size = ntohs (msg->header.size);
609 if (size <= sizeof(struct RenameMessage))
610 {
611 GNUNET_break (0);
612 return GNUNET_SYSERR;
613 }
614 old_name_len = ntohs (msg->old_name_len);
615 new_name_len = ntohs (msg->new_name_len);
616 old_name = (const char *) &msg[1];
617 new_name = &old_name[old_name_len];
618 if ((old_name_len + new_name_len + sizeof(struct RenameMessage) != size) ||
619 ('\0' != old_name[old_name_len - 1]) ||
620 ('\0' != new_name[new_name_len - 1]))
621 {
622 GNUNET_break (0);
623 return GNUNET_SYSERR;
624 }
625
626 return GNUNET_OK;
627}
628
629
630/**
631 * Handler for RENAME message from client, creates
632 * new identity.
633 *
634 * @param cls unused
635 * @param rm the message received
636 */
637static void
638handle_rename_message (void *cls, const struct RenameMessage *rm)
639{
640 uint16_t old_name_len;
641 struct Ego *ego;
642 char *old_name;
643 char *new_name;
644 struct RenameContext rename_ctx;
645 struct GNUNET_SERVICE_Client *client = cls;
646 char *fn_old;
647 char *fn_new;
648 const char *old_name_tmp;
649
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received RENAME message from client\n");
651 old_name_len = ntohs (rm->old_name_len);
652 old_name_tmp = (const char *) &rm[1];
653 old_name = GNUNET_strdup (old_name_tmp);
654 GNUNET_STRINGS_utf8_tolower (old_name_tmp, old_name);
655 new_name = GNUNET_strdup (&old_name_tmp[old_name_len]);
656 GNUNET_STRINGS_utf8_tolower (&old_name_tmp[old_name_len], new_name);
657
658 /* check if new name is already in use */
659 for (ego = ego_head; NULL != ego; ego = ego->next)
660 {
661 if (0 == strcmp (ego->identifier, new_name))
662 {
663 send_result_code (client, GNUNET_EC_IDENTITY_NAME_CONFLICT);
664 GNUNET_SERVICE_client_continue (client);
665 GNUNET_free (old_name);
666 GNUNET_free (new_name);
667 return;
668 }
669 }
670
671 /* locate old name and, if found, perform rename */
672 for (ego = ego_head; NULL != ego; ego = ego->next)
673 {
674 if (0 == strcmp (ego->identifier, old_name))
675 {
676 fn_old = get_ego_filename (ego);
677 GNUNET_free (ego->identifier);
678 rename_ctx.old_name = old_name;
679 rename_ctx.new_name = new_name;
680 GNUNET_CONFIGURATION_iterate_sections (subsystem_cfg,
681 &handle_ego_rename,
682 &rename_ctx);
683 if (GNUNET_OK !=
684 GNUNET_CONFIGURATION_write (subsystem_cfg, subsystem_cfg_file))
685 GNUNET_log (
686 GNUNET_ERROR_TYPE_ERROR,
687 _ ("Failed to write subsystem default identifier map to `%s'.\n"),
688 subsystem_cfg_file);
689 ego->identifier = GNUNET_strdup (new_name);
690 fn_new = get_ego_filename (ego);
691 if (0 != rename (fn_old, fn_new))
692 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "rename", fn_old);
693 GNUNET_free (fn_old);
694 GNUNET_free (fn_new);
695 GNUNET_free (old_name);
696 GNUNET_free (new_name);
697 notify_listeners (ego);
698 send_result_code (client, GNUNET_EC_NONE);
699 GNUNET_SERVICE_client_continue (client);
700 return;
701 }
702 }
703
704 /* failed to locate old name */
705 send_result_code (client, GNUNET_EC_IDENTITY_NOT_FOUND);
706 GNUNET_free (old_name);
707 GNUNET_free (new_name);
708 GNUNET_SERVICE_client_continue (client);
709}
710
711
712/**
713 * An ego was removed, remove it from all subsystems where it is
714 * currently set as the default.
715 *
716 * @param cls name of the removed ego (const char *)
717 * @param section a section in the configuration to process
718 */
719static void
720handle_ego_delete (void *cls, const char *section)
721{
722 const char *identifier = cls;
723 char *id;
724
725 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (subsystem_cfg,
726 section,
727 "DEFAULT_IDENTIFIER",
728 &id))
729 return;
730 if (0 != strcmp (id, identifier))
731 {
732 GNUNET_free (id);
733 return;
734 }
735 GNUNET_CONFIGURATION_set_value_string (subsystem_cfg,
736 section,
737 "DEFAULT_IDENTIFIER",
738 NULL);
739 GNUNET_free (id);
740}
741
742
743/**
744 * Checks a #GNUNET_MESSAGE_TYPE_IDENTITY_DELETE message
745 *
746 * @param cls client sending the message
747 * @param msg message of type `struct DeleteMessage`
748 * @return #GNUNET_OK if @a msg is well-formed
749 */
750static int
751check_delete_message (void *cls, const struct DeleteMessage *msg)
752{
753 uint16_t size;
754 uint16_t name_len;
755 const char *name;
756
757 size = ntohs (msg->header.size);
758 if (size <= sizeof(struct DeleteMessage))
759 {
760 GNUNET_break (0);
761 return GNUNET_SYSERR;
762 }
763 name = (const char *) &msg[1];
764 name_len = ntohs (msg->name_len);
765 if ((name_len + sizeof(struct DeleteMessage) != size) ||
766 (0 != ntohs (msg->reserved)) || ('\0' != name[name_len - 1]))
767 {
768 GNUNET_break (0);
769 return GNUNET_SYSERR;
770 }
771 return GNUNET_OK;
772}
773
774
775/**
776 * Handler for DELETE message from client, creates
777 * new identity.
778 *
779 * @param cls unused
780 * @param dm the message received
781 */
782static void
783handle_delete_message (void *cls, const struct DeleteMessage *dm)
784{
785 struct Ego *ego;
786 char *name;
787 char *fn;
788 struct GNUNET_SERVICE_Client *client = cls;
789
790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received DELETE message from client\n");
791 name = GNUNET_strdup ((const char *) &dm[1]);
792 GNUNET_STRINGS_utf8_tolower ((const char *) &dm[1], name);
793
794 for (ego = ego_head; NULL != ego; ego = ego->next)
795 {
796 if (0 == strcmp (ego->identifier, name))
797 {
798 GNUNET_CONTAINER_DLL_remove (ego_head, ego_tail, ego);
799 GNUNET_CONFIGURATION_iterate_sections (subsystem_cfg,
800 &handle_ego_delete,
801 ego->identifier);
802 if (GNUNET_OK !=
803 GNUNET_CONFIGURATION_write (subsystem_cfg, subsystem_cfg_file))
804 GNUNET_log (
805 GNUNET_ERROR_TYPE_ERROR,
806 _ ("Failed to write subsystem default identifier map to `%s'.\n"),
807 subsystem_cfg_file);
808 fn = get_ego_filename (ego);
809 if (0 != unlink (fn))
810 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", fn);
811 GNUNET_free (fn);
812 GNUNET_free (ego->identifier);
813 ego->identifier = NULL;
814 notify_listeners (ego);
815 GNUNET_free (ego);
816 GNUNET_free (name);
817 send_result_code (client, GNUNET_EC_NONE);
818 GNUNET_SERVICE_client_continue (client);
819 return;
820 }
821 }
822
823 send_result_code (client, GNUNET_EC_IDENTITY_NOT_FOUND);
824 GNUNET_free (name);
825 GNUNET_SERVICE_client_continue (client);
826}
827
828
829static int
830read_from_file (const char *filename,
831 void *buf,
832 size_t buf_size)
833{
834 int fd;
835 struct stat sb;
836
837 fd = open (filename,
838 O_RDONLY);
839 if (-1 == fd)
840 {
841 memset (buf,
842 0,
843 buf_size);
844 return GNUNET_SYSERR;
845 }
846 if (0 != fstat (fd,
847 &sb))
848 {
849 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
850 "stat",
851 filename);
852 GNUNET_assert (0 == close (fd));
853 memset (buf,
854 0,
855 buf_size);
856 return GNUNET_SYSERR;
857 }
858 if (sb.st_size != buf_size)
859 {
860 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
861 "File `%s' has wrong size (%llu), expected %llu bytes\n",
862 filename,
863 (unsigned long long) sb.st_size,
864 (unsigned long long) buf_size);
865 GNUNET_assert (0 == close (fd));
866 memset (buf,
867 0,
868 buf_size);
869 return GNUNET_SYSERR;
870 }
871 if (buf_size !=
872 read (fd,
873 buf,
874 buf_size))
875 {
876 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
877 "read",
878 filename);
879 GNUNET_assert (0 == close (fd));
880 memset (buf,
881 0,
882 buf_size);
883 return GNUNET_SYSERR;
884 }
885 GNUNET_assert (0 == close (fd));
886 return GNUNET_OK;
887}
888
889
890/**
891 * Process the given file from the "EGODIR". Parses the file
892 * and creates the respective 'struct Ego' in memory.
893 *
894 * @param cls NULL
895 * @param filename name of the file to parse
896 * @return #GNUNET_OK to continue to iterate,
897 * #GNUNET_NO to stop iteration with no error,
898 * #GNUNET_SYSERR to abort iteration with error!
899 */
900static int
901process_ego_file (void *cls,
902 const char *filename)
903{
904 struct Ego *ego;
905 const char *fn;
906
907 fn = strrchr (filename, (int) DIR_SEPARATOR);
908 if (NULL == fn)
909 {
910 GNUNET_break (0);
911 return GNUNET_OK;
912 }
913 ego = GNUNET_new (struct Ego);
914 if (GNUNET_OK !=
915 read_from_file (filename,
916 &ego->pk,
917 sizeof (ego->pk)))
918 {
919 GNUNET_free (ego);
920 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
921 _ ("Failed to parse ego information in `%s'\n"),
922 filename);
923 return GNUNET_OK;
924 }
925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
926 "Loaded ego `%s'\n",
927 fn + 1);
928 ego->identifier = GNUNET_strdup (fn + 1);
929 GNUNET_CONTAINER_DLL_insert (ego_head, ego_tail, ego);
930 return GNUNET_OK;
931}
932
933
934/**
935 * Handle network size estimate clients.
936 *
937 * @param cls closure
938 * @param server the initialized server
939 * @param c configuration to use
940 */
941static void
942run (void *cls,
943 const struct GNUNET_CONFIGURATION_Handle *c,
944 struct GNUNET_SERVICE_Handle *service)
945{
946 cfg = c;
947 nc = GNUNET_notification_context_create (1);
948 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
949 "identity",
950 "EGODIR",
951 &ego_directory))
952 {
953 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "identity", "EGODIR");
954 GNUNET_SCHEDULER_shutdown ();
955 return;
956 }
957 if (GNUNET_OK !=
958 GNUNET_CONFIGURATION_get_value_filename (cfg,
959 "identity",
960 "SUBSYSTEM_CFG",
961 &subsystem_cfg_file))
962 {
963 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
964 "identity",
965 "SUBSYSTEM_CFG");
966 GNUNET_SCHEDULER_shutdown ();
967 return;
968 }
969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
970 "Loading subsystem configuration `%s'\n",
971 subsystem_cfg_file);
972 subsystem_cfg = GNUNET_CONFIGURATION_create ();
973 if ((GNUNET_YES == GNUNET_DISK_file_test (subsystem_cfg_file)) &&
974 (GNUNET_OK !=
975 GNUNET_CONFIGURATION_parse (subsystem_cfg, subsystem_cfg_file)))
976 {
977 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
978 _ (
979 "Failed to parse subsystem identity configuration file `%s'\n"),
980 subsystem_cfg_file);
981 GNUNET_SCHEDULER_shutdown ();
982 return;
983 }
984 stats = GNUNET_STATISTICS_create ("identity", cfg);
985 if (GNUNET_OK != GNUNET_DISK_directory_create (ego_directory))
986 {
987 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
988 _ ("Failed to create directory `%s' for storing egos\n"),
989 ego_directory);
990 }
991 GNUNET_DISK_directory_scan (ego_directory,
992 &process_ego_file,
993 NULL);
994 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
995}
996
997
998/**
999 * Define "main" method using service macro.
1000 */
1001GNUNET_SERVICE_MAIN (
1002 "identity",
1003 GNUNET_SERVICE_OPTION_NONE,
1004 &run,
1005 &client_connect_cb,
1006 &client_disconnect_cb,
1007 NULL,
1008 GNUNET_MQ_hd_fixed_size (start_message,
1009 GNUNET_MESSAGE_TYPE_IDENTITY_START,
1010 struct GNUNET_MessageHeader,
1011 NULL),
1012 GNUNET_MQ_hd_var_size (lookup_message,
1013 GNUNET_MESSAGE_TYPE_IDENTITY_LOOKUP,
1014 struct LookupMessage,
1015 NULL),
1016 GNUNET_MQ_hd_var_size (lookup_by_suffix_message,
1017 GNUNET_MESSAGE_TYPE_IDENTITY_LOOKUP_BY_SUFFIX,
1018 struct LookupMessage,
1019 NULL),
1020 GNUNET_MQ_hd_var_size (create_message,
1021 GNUNET_MESSAGE_TYPE_IDENTITY_CREATE,
1022 struct CreateRequestMessage,
1023 NULL),
1024 GNUNET_MQ_hd_var_size (rename_message,
1025 GNUNET_MESSAGE_TYPE_IDENTITY_RENAME,
1026 struct RenameMessage,
1027 NULL),
1028 GNUNET_MQ_hd_var_size (delete_message,
1029 GNUNET_MESSAGE_TYPE_IDENTITY_DELETE,
1030 struct DeleteMessage,
1031 NULL),
1032 GNUNET_MQ_handler_end ());
1033
1034
1035/* end of gnunet-service-identity.c */