diff options
Diffstat (limited to 'src/service/identity/gnunet-service-identity.c')
-rw-r--r-- | src/service/identity/gnunet-service-identity.c | 1035 |
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 | */ | ||
45 | struct 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 | */ | ||
72 | static 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 | */ | ||
78 | static struct GNUNET_CONFIGURATION_Handle *subsystem_cfg; | ||
79 | |||
80 | /** | ||
81 | * Handle to the statistics service. | ||
82 | */ | ||
83 | static struct GNUNET_STATISTICS_Handle *stats; | ||
84 | |||
85 | /** | ||
86 | * Notification context, simplifies client broadcasts. | ||
87 | */ | ||
88 | static struct GNUNET_NotificationContext *nc; | ||
89 | |||
90 | /** | ||
91 | * Directory where we store the identities. | ||
92 | */ | ||
93 | static char *ego_directory; | ||
94 | |||
95 | /** | ||
96 | * Configuration file name where subsystem information is kept. | ||
97 | */ | ||
98 | static char *subsystem_cfg_file; | ||
99 | |||
100 | /** | ||
101 | * Head of DLL of all egos. | ||
102 | */ | ||
103 | static struct Ego *ego_head; | ||
104 | |||
105 | /** | ||
106 | * Tail of DLL of all egos. | ||
107 | */ | ||
108 | static 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 | */ | ||
117 | static char * | ||
118 | get_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 | */ | ||
138 | static void | ||
139 | client_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 | */ | ||
157 | static void * | ||
158 | client_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 | */ | ||
171 | static void | ||
172 | shutdown_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 | */ | ||
209 | static void | ||
210 | send_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 | */ | ||
233 | static struct GNUNET_MQ_Envelope * | ||
234 | create_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 | */ | ||
265 | static void | ||
266 | handle_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 | */ | ||
307 | static int | ||
308 | check_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 | */ | ||
323 | static void | ||
324 | handle_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 | */ | ||
357 | static int | ||
358 | check_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 | */ | ||
373 | static void | ||
374 | handle_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 | */ | ||
417 | static void | ||
418 | notify_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 | */ | ||
448 | static int | ||
449 | check_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 | */ | ||
486 | static void | ||
487 | handle_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 | */ | ||
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 | * 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 | */ | ||
568 | static void | ||
569 | handle_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 | */ | ||
599 | static int | ||
600 | check_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 | */ | ||
637 | static void | ||
638 | handle_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 | */ | ||
719 | static void | ||
720 | handle_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 | */ | ||
750 | static int | ||
751 | check_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 | */ | ||
782 | static void | ||
783 | handle_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 | |||
829 | static int | ||
830 | read_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 | */ | ||
900 | static int | ||
901 | process_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 | */ | ||
941 | static void | ||
942 | run (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 | */ | ||
1001 | GNUNET_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 */ | ||