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.
17 * @file identity/identity_api.c
18 * @brief api to interact with the identity service
19 * @author Christian Grothoff
22 #include "gnunet_util_lib.h"
23 #include "gnunet_constants.h"
24 #include "gnunet_protocols.h"
25 #include "gnunet_identity_service.h"
28 #define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__)
33 struct GNUNET_IDENTITY_Ego
36 * Private key associated with this ego.
38 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
41 * Current name associated with this ego.
46 * Client context associated with this ego.
51 * Hash of the public key of this ego.
53 struct GNUNET_HashCode id;
58 * Handle for an operation with the identity service.
60 struct GNUNET_IDENTITY_Operation
64 * Main identity handle.
66 struct GNUNET_IDENTITY_Handle *h;
69 * We keep operations in a DLL.
71 struct GNUNET_IDENTITY_Operation *next;
74 * We keep operations in a DLL.
76 struct GNUNET_IDENTITY_Operation *prev;
79 * Message to send to the identity service.
80 * Allocated at the end of this struct.
82 const struct GNUNET_MessageHeader *msg;
85 * Continuation to invoke with the result of the transmission; @e cb
86 * will be NULL in this case.
88 GNUNET_IDENTITY_Continuation cont;
91 * Continuation to invoke with the result of the transmission for
92 * 'get' operations (@e cont will be NULL in this case).
94 GNUNET_IDENTITY_Callback cb;
97 * Closure for @e cont or @e cb.
105 * Handle for the service.
107 struct GNUNET_IDENTITY_Handle
110 * Configuration to use.
112 const struct GNUNET_CONFIGURATION_Handle *cfg;
115 * Connection to service.
117 struct GNUNET_MQ_Handle *mq;
120 * Hash map from the hash of the public key to the
121 * respective `GNUNET_IDENTITY_Ego` handle.
123 struct GNUNET_CONTAINER_MultiHashMap *egos;
126 * Function to call when we receive updates.
128 GNUNET_IDENTITY_Callback cb;
136 * Head of active operations.
138 struct GNUNET_IDENTITY_Operation *op_head;
141 * Tail of active operations.
143 struct GNUNET_IDENTITY_Operation *op_tail;
146 * Task doing exponential back-off trying to reconnect.
148 struct GNUNET_SCHEDULER_Task *reconnect_task;
151 * Time for next connect retry.
153 struct GNUNET_TIME_Relative reconnect_delay;
156 * Are we polling for incoming messages right now?
164 * Obtain the ego representing 'anonymous' users.
166 * @return handle for the anonymous user, must not be freed
168 const struct GNUNET_IDENTITY_Ego *
169 GNUNET_IDENTITY_ego_get_anonymous ()
171 static struct GNUNET_IDENTITY_Ego anon;
172 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
176 anon.pk = (struct GNUNET_CRYPTO_EcdsaPrivateKey *) GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
177 GNUNET_CRYPTO_ecdsa_key_get_public (anon.pk,
179 GNUNET_CRYPTO_hash (&pub,
187 * Try again to connect to the identity service.
189 * @param cls handle to the identity service.
192 reconnect (void *cls);
196 * Free ego from hash map.
198 * @param cls identity service handle
200 * @param value ego to free
201 * @return #GNUNET_OK (continue to iterate)
205 const struct GNUNET_HashCode *key,
208 struct GNUNET_IDENTITY_Handle *h = cls;
209 struct GNUNET_IDENTITY_Ego *ego = value;
216 GNUNET_free (ego->pk);
217 GNUNET_free (ego->name);
218 GNUNET_assert (GNUNET_YES ==
219 GNUNET_CONTAINER_multihashmap_remove (h->egos,
228 * Reschedule a connect attempt to the service.
230 * @param h transport service to reconnect
233 reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
235 struct GNUNET_IDENTITY_Operation *op;
237 GNUNET_assert (NULL == h->reconnect_task);
241 GNUNET_MQ_destroy (h->mq);
244 while (NULL != (op = h->op_head))
246 GNUNET_CONTAINER_DLL_remove (h->op_head,
249 if (NULL != op->cont)
251 "Error in communication with the identity service");
252 else if (NULL != op->cb)
259 GNUNET_CONTAINER_multihashmap_iterate (h->egos,
262 LOG (GNUNET_ERROR_TYPE_DEBUG,
263 "Scheduling task to reconnect to identity service in %s.\n",
264 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay,
267 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
270 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
275 * Generic error handler, called with the appropriate error code and
276 * the same closure specified at the creation of the message queue.
277 * Not every message queue implementation supports an error handler.
279 * @param cls closure with the `struct GNUNET_IDENTITY_Handle *`
280 * @param error error code
283 mq_error_handler (void *cls,
284 enum GNUNET_MQ_Error error)
286 struct GNUNET_IDENTITY_Handle *h = cls;
288 reschedule_connect (h);
293 * We received a result code from the service. Check the message
297 * @param rcm result message received
298 * @return #GNUNET_OK if the message is well-formed
301 check_identity_result_code (void *cls,
302 const struct ResultCodeMessage *rcm)
304 uint16_t size = ntohs (rcm->header.size) - sizeof (*rcm);
305 const char *str = (const char *) &rcm[1];
309 if ('\0' != str[size - 1])
312 return GNUNET_SYSERR;
319 * We received a result code from the service.
322 * @param rcm result message received
325 handle_identity_result_code (void *cls,
326 const struct ResultCodeMessage *rcm)
328 struct GNUNET_IDENTITY_Handle *h = cls;
329 struct GNUNET_IDENTITY_Operation *op;
330 uint16_t size = ntohs (rcm->header.size) - sizeof (*rcm);
331 const char *str = (0 == size) ? NULL : (const char *) &rcm[1];
337 reschedule_connect (h);
340 GNUNET_CONTAINER_DLL_remove (h->op_head,
343 if (NULL != op->cont)
346 else if (NULL != op->cb)
347 op->cb (op->cls, NULL, NULL, NULL);
353 * Check validity of identity update message.
356 * @param um message received
357 * @return #GNUNET_OK if the message is well-formed
360 check_identity_update (void *cls,
361 const struct UpdateMessage *um)
363 uint16_t size = ntohs (um->header.size);
364 uint16_t name_len = ntohs (um->name_len);
365 const char *str = (const char *) &um[1];
367 if ( (size != name_len + sizeof (struct UpdateMessage)) ||
369 ('\0' != str[name_len - 1])) )
372 return GNUNET_SYSERR;
379 * Handle identity update message.
382 * @param um message received
385 handle_identity_update (void *cls,
386 const struct UpdateMessage *um)
388 struct GNUNET_IDENTITY_Handle *h = cls;
389 uint16_t name_len = ntohs (um->name_len);
390 const char *str = (0 == name_len) ? NULL : (const char *) &um[1];
391 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
392 struct GNUNET_HashCode id;
393 struct GNUNET_IDENTITY_Ego *ego;
395 if (GNUNET_YES == ntohs (um->end_of_list))
397 /* end of initial list of data */
405 GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key,
407 GNUNET_CRYPTO_hash (&pub,
410 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
414 /* ego was created */
417 /* deletion of unknown ego? not allowed */
419 reschedule_connect (h);
422 ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
423 ego->pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
424 *ego->pk = um->private_key;
425 ego->name = GNUNET_strdup (str);
427 GNUNET_assert (GNUNET_YES ==
428 GNUNET_CONTAINER_multihashmap_put (h->egos,
431 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
435 /* ego was deleted */
436 GNUNET_assert (GNUNET_YES ==
437 GNUNET_CONTAINER_multihashmap_remove (h->egos,
443 /* ego changed name */
444 GNUNET_free (ego->name);
445 ego->name = GNUNET_strdup (str);
447 /* inform application about change */
453 /* complete deletion */
456 GNUNET_free (ego->pk);
457 GNUNET_free (ego->name);
464 * Function called when we receive a set default message from the
468 * @param sdm message received
469 * @return #GNUNET_OK if the message is well-formed
472 check_identity_set_default (void *cls,
473 const struct SetDefaultMessage *sdm)
475 uint16_t size = ntohs (sdm->header.size) - sizeof (*sdm);
476 uint16_t name_len = ntohs (sdm->name_len);
477 const char *str = (const char *) &sdm[1];
479 if ( (size != name_len) ||
481 ('\0' != str[name_len - 1]) ) )
484 return GNUNET_SYSERR;
486 GNUNET_break (0 == ntohs (sdm->reserved));
492 * Type of a function to call when we receive a message
496 * @param sdm message received
499 handle_identity_set_default (void *cls,
500 const struct SetDefaultMessage *sdm)
502 struct GNUNET_IDENTITY_Handle *h = cls;
503 struct GNUNET_IDENTITY_Operation *op;
504 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
505 struct GNUNET_HashCode id;
506 struct GNUNET_IDENTITY_Ego *ego;
508 GNUNET_CRYPTO_ecdsa_key_get_public (&sdm->private_key,
510 GNUNET_CRYPTO_hash (&pub,
513 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
518 reschedule_connect (h);
525 reschedule_connect (h);
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 "Received SET_DEFAULT message from identity service\n");
530 GNUNET_CONTAINER_DLL_remove (h->op_head,
543 * Try again to connect to the identity service.
545 * @param cls handle to the identity service.
548 reconnect (void *cls)
550 struct GNUNET_IDENTITY_Handle *h = cls;
551 struct GNUNET_MQ_MessageHandler handlers[] = {
552 GNUNET_MQ_hd_var_size (identity_result_code,
553 GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
554 struct ResultCodeMessage,
556 GNUNET_MQ_hd_var_size (identity_update,
557 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
558 struct UpdateMessage,
560 GNUNET_MQ_hd_var_size (identity_set_default,
561 GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT,
562 struct SetDefaultMessage,
564 GNUNET_MQ_handler_end ()
566 struct GNUNET_MQ_Envelope *env;
567 struct GNUNET_MessageHeader *msg;
569 h->reconnect_task = NULL;
570 LOG (GNUNET_ERROR_TYPE_DEBUG,
571 "Connecting to identity service.\n");
572 GNUNET_assert (NULL == h->mq);
573 h->mq = GNUNET_CLIENT_connect (h->cfg,
580 env = GNUNET_MQ_msg (msg,
581 GNUNET_MESSAGE_TYPE_IDENTITY_START);
582 GNUNET_MQ_send (h->mq,
588 * Connect to the identity service.
590 * @param cfg the configuration to use
591 * @param cb function to call on all identity events, can be NULL
592 * @param cb_cls closure for @a cb
593 * @return handle to use
595 struct GNUNET_IDENTITY_Handle *
596 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
597 GNUNET_IDENTITY_Callback cb,
600 struct GNUNET_IDENTITY_Handle *h;
602 h = GNUNET_new (struct GNUNET_IDENTITY_Handle);
606 h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
618 * Obtain the ECC key associated with a ego.
621 * @return associated ECC key, valid as long as the ego is valid
623 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
624 GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
631 * Get the identifier (public key) of an ego.
633 * @param ego identity handle with the private key
634 * @param pk set to ego's public key
637 GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
638 struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
640 GNUNET_CRYPTO_ecdsa_key_get_public (ego->pk,
646 * Obtain the identity that is currently preferred/default
649 * @param h identity service to query
650 * @param service_name for which service is an identity wanted
651 * @param cb function to call with the result (will only be called once)
652 * @param cb_cls closure for @a cb
653 * @return handle to abort the operation
655 struct GNUNET_IDENTITY_Operation *
656 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *h,
657 const char *service_name,
658 GNUNET_IDENTITY_Callback cb,
661 struct GNUNET_IDENTITY_Operation *op;
662 struct GNUNET_MQ_Envelope *env;
663 struct GetDefaultMessage *gdm;
668 slen = strlen (service_name) + 1;
669 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct GetDefaultMessage))
674 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
678 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
681 env = GNUNET_MQ_msg_extra (gdm,
683 GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT);
684 gdm->name_len = htons (slen);
685 gdm->reserved = htons (0);
686 GNUNET_memcpy (&gdm[1],
689 GNUNET_MQ_send (h->mq,
696 * Set the preferred/default identity for a service.
698 * @param h identity service to inform
699 * @param service_name for which service is an identity set
700 * @param ego new default identity to be set for this service
701 * @param cont function to call once the operation finished
702 * @param cont_cls closure for @a cont
703 * @return handle to abort the operation
705 struct GNUNET_IDENTITY_Operation *
706 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *h,
707 const char *service_name,
708 struct GNUNET_IDENTITY_Ego *ego,
709 GNUNET_IDENTITY_Continuation cont,
712 struct GNUNET_IDENTITY_Operation *op;
713 struct GNUNET_MQ_Envelope *env;
714 struct SetDefaultMessage *sdm;
719 slen = strlen (service_name) + 1;
720 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct SetDefaultMessage))
725 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
729 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
732 env = GNUNET_MQ_msg_extra (sdm,
734 GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
735 sdm->name_len = htons (slen);
736 sdm->reserved = htons (0);
737 sdm->private_key = *ego->pk;
738 GNUNET_memcpy (&sdm[1],
741 GNUNET_MQ_send (h->mq,
748 * Create a new identity with the given name.
750 * @param h identity service to use
751 * @param name desired name
752 * @param cont function to call with the result (will only be called once)
753 * @param cont_cls closure for @a cont
754 * @return handle to abort the operation
756 struct GNUNET_IDENTITY_Operation *
757 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
759 GNUNET_IDENTITY_Continuation cont,
762 struct GNUNET_IDENTITY_Operation *op;
763 struct GNUNET_MQ_Envelope *env;
764 struct CreateRequestMessage *crm;
765 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
770 slen = strlen (name) + 1;
771 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct CreateRequestMessage))
776 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
780 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
783 env = GNUNET_MQ_msg_extra (crm,
785 GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
786 crm->name_len = htons (slen);
787 crm->reserved = htons (0);
788 pk = GNUNET_CRYPTO_ecdsa_key_create ();
789 crm->private_key = *pk;
791 GNUNET_memcpy (&crm[1],
794 GNUNET_MQ_send (h->mq,
801 * Renames an existing identity.
803 * @param h identity service to use
804 * @param old_name old name
805 * @param new_name desired new name
806 * @param cb function to call with the result (will only be called once)
807 * @param cb_cls closure for @a cb
808 * @return handle to abort the operation
810 struct GNUNET_IDENTITY_Operation *
811 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
812 const char *old_name,
813 const char *new_name,
814 GNUNET_IDENTITY_Continuation cb,
817 struct GNUNET_IDENTITY_Operation *op;
818 struct GNUNET_MQ_Envelope *env;
819 struct RenameMessage *grm;
826 slen_old = strlen (old_name) + 1;
827 slen_new = strlen (new_name) + 1;
828 if ( (slen_old >= GNUNET_MAX_MESSAGE_SIZE) ||
829 (slen_new >= GNUNET_MAX_MESSAGE_SIZE) ||
830 (slen_old + slen_new >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct RenameMessage)) )
835 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
839 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
842 env = GNUNET_MQ_msg_extra (grm,
844 GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
845 grm->old_name_len = htons (slen_old);
846 grm->new_name_len = htons (slen_new);
847 dst = (char *) &grm[1];
851 GNUNET_memcpy (&dst[slen_old],
854 GNUNET_MQ_send (h->mq,
861 * Delete an existing identity.
863 * @param h identity service to use
864 * @param name name of the identity to delete
865 * @param cb function to call with the result (will only be called once)
866 * @param cb_cls closure for @a cb
867 * @return handle to abort the operation
869 struct GNUNET_IDENTITY_Operation *
870 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
872 GNUNET_IDENTITY_Continuation cb,
875 struct GNUNET_IDENTITY_Operation *op;
876 struct GNUNET_MQ_Envelope *env;
877 struct DeleteMessage *gdm;
882 slen = strlen (name) + 1;
883 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (struct DeleteMessage))
888 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
892 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
895 env = GNUNET_MQ_msg_extra (gdm,
897 GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
898 gdm->name_len = htons (slen);
899 gdm->reserved = htons (0);
900 GNUNET_memcpy (&gdm[1],
903 GNUNET_MQ_send (h->mq,
910 * Cancel an identity operation. Note that the operation MAY still
911 * be executed; this merely cancels the continuation; if the request
912 * was already transmitted, the service may still choose to complete
915 * @param op operation to cancel
918 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
926 * Disconnect from identity service
928 * @param h handle to destroy
931 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
933 struct GNUNET_IDENTITY_Operation *op;
935 GNUNET_assert (NULL != h);
936 if (h->reconnect_task != NULL)
938 GNUNET_SCHEDULER_cancel (h->reconnect_task);
939 h->reconnect_task = NULL;
943 GNUNET_CONTAINER_multihashmap_iterate (h->egos,
946 GNUNET_CONTAINER_multihashmap_destroy (h->egos);
949 while (NULL != (op = h->op_head))
951 GNUNET_break (NULL == op->cont);
952 GNUNET_CONTAINER_DLL_remove (h->op_head,
959 GNUNET_MQ_destroy (h->mq);
965 /* end of identity_api.c */