2 This file is part of GNUnet.
3 Copyright (C) 2013, 2016 GNUnet e.V.
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.
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.
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/>.
20 * @file identity/identity_api.c
21 * @brief api to interact with the identity service
22 * @author Christian Grothoff
25 #include "gnunet_util_lib.h"
26 #include "gnunet_constants.h"
27 #include "gnunet_protocols.h"
28 #include "gnunet_identity_service.h"
31 #define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__)
36 struct GNUNET_IDENTITY_Ego
39 * Private key associated with this ego.
41 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
44 * Current name associated with this ego.
49 * Client context associated with this ego.
54 * Hash of the public key of this ego.
56 struct GNUNET_HashCode id;
61 * Handle for an operation with the identity service.
63 struct GNUNET_IDENTITY_Operation
67 * Main identity handle.
69 struct GNUNET_IDENTITY_Handle *h;
72 * We keep operations in a DLL.
74 struct GNUNET_IDENTITY_Operation *next;
77 * We keep operations in a DLL.
79 struct GNUNET_IDENTITY_Operation *prev;
82 * Message to send to the identity service.
83 * Allocated at the end of this struct.
85 const struct GNUNET_MessageHeader *msg;
88 * Continuation to invoke with the result of the transmission; @e cb
89 * will be NULL in this case.
91 GNUNET_IDENTITY_Continuation cont;
94 * Continuation to invoke with the result of the transmission for
95 * 'get' operations (@e cont will be NULL in this case).
97 GNUNET_IDENTITY_Callback cb;
100 * Closure for @e cont or @e cb.
108 * Handle for the service.
110 struct GNUNET_IDENTITY_Handle
113 * Configuration to use.
115 const struct GNUNET_CONFIGURATION_Handle *cfg;
118 * Connection to service.
120 struct GNUNET_MQ_Handle *mq;
123 * Hash map from the hash of the public key to the
124 * respective `GNUNET_IDENTITY_Ego` handle.
126 struct GNUNET_CONTAINER_MultiHashMap *egos;
129 * Function to call when we receive updates.
131 GNUNET_IDENTITY_Callback cb;
139 * Head of active operations.
141 struct GNUNET_IDENTITY_Operation *op_head;
144 * Tail of active operations.
146 struct GNUNET_IDENTITY_Operation *op_tail;
149 * Task doing exponential back-off trying to reconnect.
151 struct GNUNET_SCHEDULER_Task *reconnect_task;
154 * Time for next connect retry.
156 struct GNUNET_TIME_Relative reconnect_delay;
159 * Are we polling for incoming messages right now?
167 * Obtain the ego representing 'anonymous' users.
169 * @return handle for the anonymous user, must not be freed
171 const struct GNUNET_IDENTITY_Ego *
172 GNUNET_IDENTITY_ego_get_anonymous ()
174 static struct GNUNET_IDENTITY_Ego anon;
175 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
179 anon.pk = (struct GNUNET_CRYPTO_EcdsaPrivateKey *) GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
180 GNUNET_CRYPTO_ecdsa_key_get_public (anon.pk,
182 GNUNET_CRYPTO_hash (&pub,
190 * Try again to connect to the identity service.
192 * @param cls handle to the identity service.
195 reconnect (void *cls);
199 * Free ego from hash map.
201 * @param cls identity service handle
203 * @param value ego to free
204 * @return #GNUNET_OK (continue to iterate)
208 const struct GNUNET_HashCode *key,
211 struct GNUNET_IDENTITY_Handle *h = cls;
212 struct GNUNET_IDENTITY_Ego *ego = value;
219 GNUNET_free (ego->pk);
220 GNUNET_free (ego->name);
221 GNUNET_assert (GNUNET_YES ==
222 GNUNET_CONTAINER_multihashmap_remove (h->egos,
231 * Reschedule a connect attempt to the service.
233 * @param h transport service to reconnect
236 reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
238 struct GNUNET_IDENTITY_Operation *op;
240 GNUNET_assert (NULL == h->reconnect_task);
244 GNUNET_MQ_destroy (h->mq);
247 while (NULL != (op = h->op_head))
249 GNUNET_CONTAINER_DLL_remove (h->op_head,
252 if (NULL != op->cont)
254 "Error in communication with the identity service");
255 else if (NULL != op->cb)
262 GNUNET_CONTAINER_multihashmap_iterate (h->egos,
265 LOG (GNUNET_ERROR_TYPE_DEBUG,
266 "Scheduling task to reconnect to identity service in %s.\n",
267 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay,
270 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
273 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
278 * Generic error handler, called with the appropriate error code and
279 * the same closure specified at the creation of the message queue.
280 * Not every message queue implementation supports an error handler.
282 * @param cls closure with the `struct GNUNET_IDENTITY_Handle *`
283 * @param error error code
286 mq_error_handler (void *cls,
287 enum GNUNET_MQ_Error error)
289 struct GNUNET_IDENTITY_Handle *h = cls;
291 reschedule_connect (h);
296 * We received a result code from the service. Check the message
300 * @param rcm result message received
301 * @return #GNUNET_OK if the message is well-formed
304 check_identity_result_code (void *cls,
305 const struct ResultCodeMessage *rcm)
307 uint16_t size = ntohs (rcm->header.size) - sizeof (*rcm);
308 const char *str = (const char *) &rcm[1];
312 if ('\0' != str[size - 1])
315 return GNUNET_SYSERR;
322 * We received a result code from the service.
325 * @param rcm result message received
328 handle_identity_result_code (void *cls,
329 const struct ResultCodeMessage *rcm)
331 struct GNUNET_IDENTITY_Handle *h = cls;
332 struct GNUNET_IDENTITY_Operation *op;
333 uint16_t size = ntohs (rcm->header.size) - sizeof (*rcm);
334 const char *str = (0 == size) ? NULL : (const char *) &rcm[1];
340 reschedule_connect (h);
343 GNUNET_CONTAINER_DLL_remove (h->op_head,
346 if (NULL != op->cont)
349 else if (NULL != op->cb)
350 op->cb (op->cls, NULL, NULL, NULL);
356 * Check validity of identity update message.
359 * @param um message received
360 * @return #GNUNET_OK if the message is well-formed
363 check_identity_update (void *cls,
364 const struct UpdateMessage *um)
366 uint16_t size = ntohs (um->header.size);
367 uint16_t name_len = ntohs (um->name_len);
368 const char *str = (const char *) &um[1];
370 if ( (size != name_len + sizeof (struct UpdateMessage)) ||
372 ('\0' != str[name_len - 1])) )
375 return GNUNET_SYSERR;
382 * Handle identity update message.
385 * @param um message received
388 handle_identity_update (void *cls,
389 const struct UpdateMessage *um)
391 struct GNUNET_IDENTITY_Handle *h = cls;
392 uint16_t name_len = ntohs (um->name_len);
393 const char *str = (0 == name_len) ? NULL : (const char *) &um[1];
394 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
395 struct GNUNET_HashCode id;
396 struct GNUNET_IDENTITY_Ego *ego;
398 if (GNUNET_YES == ntohs (um->end_of_list))
400 /* end of initial list of data */
408 GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key,
410 GNUNET_CRYPTO_hash (&pub,
413 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
417 /* ego was created */
420 /* deletion of unknown ego? not allowed */
422 reschedule_connect (h);
425 ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
426 ego->pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
427 *ego->pk = um->private_key;
428 ego->name = GNUNET_strdup (str);
430 GNUNET_assert (GNUNET_YES ==
431 GNUNET_CONTAINER_multihashmap_put (h->egos,
434 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
438 /* ego was deleted */
439 GNUNET_assert (GNUNET_YES ==
440 GNUNET_CONTAINER_multihashmap_remove (h->egos,
446 /* ego changed name */
447 GNUNET_free (ego->name);
448 ego->name = GNUNET_strdup (str);
450 /* inform application about change */
456 /* complete deletion */
459 GNUNET_free (ego->pk);
460 GNUNET_free (ego->name);
467 * Function called when we receive a set default message from the
471 * @param sdm message received
472 * @return #GNUNET_OK if the message is well-formed
475 check_identity_set_default (void *cls,
476 const struct SetDefaultMessage *sdm)
478 uint16_t size = ntohs (sdm->header.size) - sizeof (*sdm);
479 uint16_t name_len = ntohs (sdm->name_len);
480 const char *str = (const char *) &sdm[1];
482 if ( (size != name_len) ||
484 ('\0' != str[name_len - 1]) ) )
487 return GNUNET_SYSERR;
489 GNUNET_break (0 == ntohs (sdm->reserved));
495 * Type of a function to call when we receive a message
499 * @param sdm message received
502 handle_identity_set_default (void *cls,
503 const struct SetDefaultMessage *sdm)
505 struct GNUNET_IDENTITY_Handle *h = cls;
506 struct GNUNET_IDENTITY_Operation *op;
507 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
508 struct GNUNET_HashCode id;
509 struct GNUNET_IDENTITY_Ego *ego;
511 GNUNET_CRYPTO_ecdsa_key_get_public (&sdm->private_key,
513 GNUNET_CRYPTO_hash (&pub,
516 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
521 reschedule_connect (h);
528 reschedule_connect (h);
531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
532 "Received SET_DEFAULT message from identity service\n");
533 GNUNET_CONTAINER_DLL_remove (h->op_head,
546 * Try again to connect to the identity service.
548 * @param cls handle to the identity service.
551 reconnect (void *cls)
553 struct GNUNET_IDENTITY_Handle *h = cls;
554 struct GNUNET_MQ_MessageHandler handlers[] = {
555 GNUNET_MQ_hd_var_size (identity_result_code,
556 GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
557 struct ResultCodeMessage,
559 GNUNET_MQ_hd_var_size (identity_update,
560 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
561 struct UpdateMessage,
563 GNUNET_MQ_hd_var_size (identity_set_default,
564 GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT,
565 struct SetDefaultMessage,
567 GNUNET_MQ_handler_end ()
569 struct GNUNET_MQ_Envelope *env;
570 struct GNUNET_MessageHeader *msg;
572 h->reconnect_task = NULL;
573 LOG (GNUNET_ERROR_TYPE_DEBUG,
574 "Connecting to identity service.\n");
575 GNUNET_assert (NULL == h->mq);
576 h->mq = GNUNET_CLIENT_connect (h->cfg,
583 env = GNUNET_MQ_msg (msg,
584 GNUNET_MESSAGE_TYPE_IDENTITY_START);
585 GNUNET_MQ_send (h->mq,
591 * Connect to the identity service.
593 * @param cfg the configuration to use
594 * @param cb function to call on all identity events, can be NULL
595 * @param cb_cls closure for @a cb
596 * @return handle to use
598 struct GNUNET_IDENTITY_Handle *
599 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
600 GNUNET_IDENTITY_Callback cb,
603 struct GNUNET_IDENTITY_Handle *h;
605 h = GNUNET_new (struct GNUNET_IDENTITY_Handle);
609 h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
621 * Obtain the ECC key associated with a ego.
624 * @return associated ECC key, valid as long as the ego is valid
626 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
627 GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
634 * Get the identifier (public key) of an ego.
636 * @param ego identity handle with the private key
637 * @param pk set to ego's public key
640 GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
641 struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
643 GNUNET_CRYPTO_ecdsa_key_get_public (ego->pk,
649 * Obtain the identity that is currently preferred/default
652 * @param h identity service to query
653 * @param service_name for which service is an identity wanted
654 * @param cb function to call with the result (will only be called once)
655 * @param cb_cls closure for @a cb
656 * @return handle to abort the operation
658 struct GNUNET_IDENTITY_Operation *
659 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *h,
660 const char *service_name,
661 GNUNET_IDENTITY_Callback cb,
664 struct GNUNET_IDENTITY_Operation *op;
665 struct GNUNET_MQ_Envelope *env;
666 struct GetDefaultMessage *gdm;
671 slen = strlen (service_name) + 1;
672 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct GetDefaultMessage))
677 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
681 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
684 env = GNUNET_MQ_msg_extra (gdm,
686 GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT);
687 gdm->name_len = htons (slen);
688 gdm->reserved = htons (0);
689 GNUNET_memcpy (&gdm[1],
692 GNUNET_MQ_send (h->mq,
699 * Set the preferred/default identity for a service.
701 * @param h identity service to inform
702 * @param service_name for which service is an identity set
703 * @param ego new default identity to be set for this service
704 * @param cont function to call once the operation finished
705 * @param cont_cls closure for @a cont
706 * @return handle to abort the operation
708 struct GNUNET_IDENTITY_Operation *
709 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *h,
710 const char *service_name,
711 struct GNUNET_IDENTITY_Ego *ego,
712 GNUNET_IDENTITY_Continuation cont,
715 struct GNUNET_IDENTITY_Operation *op;
716 struct GNUNET_MQ_Envelope *env;
717 struct SetDefaultMessage *sdm;
722 slen = strlen (service_name) + 1;
723 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct SetDefaultMessage))
728 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
732 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
735 env = GNUNET_MQ_msg_extra (sdm,
737 GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
738 sdm->name_len = htons (slen);
739 sdm->reserved = htons (0);
740 sdm->private_key = *ego->pk;
741 GNUNET_memcpy (&sdm[1],
744 GNUNET_MQ_send (h->mq,
751 * Create a new identity with the given name.
753 * @param h identity service to use
754 * @param name desired name
755 * @param cont function to call with the result (will only be called once)
756 * @param cont_cls closure for @a cont
757 * @return handle to abort the operation
759 struct GNUNET_IDENTITY_Operation *
760 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
762 GNUNET_IDENTITY_Continuation cont,
765 struct GNUNET_IDENTITY_Operation *op;
766 struct GNUNET_MQ_Envelope *env;
767 struct CreateRequestMessage *crm;
768 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
773 slen = strlen (name) + 1;
774 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct CreateRequestMessage))
779 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
783 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
786 env = GNUNET_MQ_msg_extra (crm,
788 GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
789 crm->name_len = htons (slen);
790 crm->reserved = htons (0);
791 pk = GNUNET_CRYPTO_ecdsa_key_create ();
792 crm->private_key = *pk;
794 GNUNET_memcpy (&crm[1],
797 GNUNET_MQ_send (h->mq,
804 * Renames an existing identity.
806 * @param h identity service to use
807 * @param old_name old name
808 * @param new_name desired new name
809 * @param cb function to call with the result (will only be called once)
810 * @param cb_cls closure for @a cb
811 * @return handle to abort the operation
813 struct GNUNET_IDENTITY_Operation *
814 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
815 const char *old_name,
816 const char *new_name,
817 GNUNET_IDENTITY_Continuation cb,
820 struct GNUNET_IDENTITY_Operation *op;
821 struct GNUNET_MQ_Envelope *env;
822 struct RenameMessage *grm;
829 slen_old = strlen (old_name) + 1;
830 slen_new = strlen (new_name) + 1;
831 if ( (slen_old >= GNUNET_MAX_MESSAGE_SIZE) ||
832 (slen_new >= GNUNET_MAX_MESSAGE_SIZE) ||
833 (slen_old + slen_new >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct RenameMessage)) )
838 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
842 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
845 env = GNUNET_MQ_msg_extra (grm,
847 GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
848 grm->old_name_len = htons (slen_old);
849 grm->new_name_len = htons (slen_new);
850 dst = (char *) &grm[1];
854 GNUNET_memcpy (&dst[slen_old],
857 GNUNET_MQ_send (h->mq,
864 * Delete an existing identity.
866 * @param h identity service to use
867 * @param name name of the identity to delete
868 * @param cb function to call with the result (will only be called once)
869 * @param cb_cls closure for @a cb
870 * @return handle to abort the operation
872 struct GNUNET_IDENTITY_Operation *
873 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
875 GNUNET_IDENTITY_Continuation cb,
878 struct GNUNET_IDENTITY_Operation *op;
879 struct GNUNET_MQ_Envelope *env;
880 struct DeleteMessage *gdm;
885 slen = strlen (name) + 1;
886 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct DeleteMessage))
891 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
895 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
898 env = GNUNET_MQ_msg_extra (gdm,
900 GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
901 gdm->name_len = htons (slen);
902 gdm->reserved = htons (0);
903 GNUNET_memcpy (&gdm[1],
906 GNUNET_MQ_send (h->mq,
913 * Cancel an identity operation. Note that the operation MAY still
914 * be executed; this merely cancels the continuation; if the request
915 * was already transmitted, the service may still choose to complete
918 * @param op operation to cancel
921 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
929 * Disconnect from identity service
931 * @param h handle to destroy
934 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
936 struct GNUNET_IDENTITY_Operation *op;
938 GNUNET_assert (NULL != h);
939 if (h->reconnect_task != NULL)
941 GNUNET_SCHEDULER_cancel (h->reconnect_task);
942 h->reconnect_task = NULL;
946 GNUNET_CONTAINER_multihashmap_iterate (h->egos,
949 GNUNET_CONTAINER_multihashmap_destroy (h->egos);
952 while (NULL != (op = h->op_head))
954 GNUNET_break (NULL == op->cont);
955 GNUNET_CONTAINER_DLL_remove (h->op_head,
962 GNUNET_MQ_destroy (h->mq);
968 /* end of identity_api.c */