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
6 it under the terms of the GNU General Public Liceidentity as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public Liceidentity for more details.
15 You should have received a copy of the GNU General Public Liceidentity
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file identity/identity_api.c
23 * @brief api to interact with the identity service
24 * @author Christian Grothoff
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_identity_service.h"
33 #define LOG(kind,...) GNUNET_log_from (kind, "identity-api",__VA_ARGS__)
38 struct GNUNET_IDENTITY_Ego
41 * Private key associated with this ego.
43 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
46 * Current name associated with this ego.
51 * Client context associated with this ego.
56 * Hash of the public key of this ego.
58 struct GNUNET_HashCode id;
63 * Handle for an operation with the identity service.
65 struct GNUNET_IDENTITY_Operation
69 * Main identity handle.
71 struct GNUNET_IDENTITY_Handle *h;
74 * We keep operations in a DLL.
76 struct GNUNET_IDENTITY_Operation *next;
79 * We keep operations in a DLL.
81 struct GNUNET_IDENTITY_Operation *prev;
84 * Message to send to the identity service.
85 * Allocated at the end of this struct.
87 const struct GNUNET_MessageHeader *msg;
90 * Continuation to invoke with the result of the transmission; @e cb
91 * will be NULL in this case.
93 GNUNET_IDENTITY_Continuation cont;
96 * Continuation to invoke with the result of the transmission for
97 * 'get' operations (@e cont will be NULL in this case).
99 GNUNET_IDENTITY_Callback cb;
102 * Closure for @e cont or @e cb.
110 * Handle for the service.
112 struct GNUNET_IDENTITY_Handle
115 * Configuration to use.
117 const struct GNUNET_CONFIGURATION_Handle *cfg;
120 * Connection to service.
122 struct GNUNET_MQ_Handle *mq;
125 * Hash map from the hash of the public key to the
126 * respective `GNUNET_IDENTITY_Ego` handle.
128 struct GNUNET_CONTAINER_MultiHashMap *egos;
131 * Function to call when we receive updates.
133 GNUNET_IDENTITY_Callback cb;
141 * Head of active operations.
143 struct GNUNET_IDENTITY_Operation *op_head;
146 * Tail of active operations.
148 struct GNUNET_IDENTITY_Operation *op_tail;
151 * Task doing exponential back-off trying to reconnect.
153 struct GNUNET_SCHEDULER_Task *reconnect_task;
156 * Time for next connect retry.
158 struct GNUNET_TIME_Relative reconnect_delay;
161 * Are we polling for incoming messages right now?
169 * Obtain the ego representing 'anonymous' users.
171 * @return handle for the anonymous user, must not be freed
173 const struct GNUNET_IDENTITY_Ego *
174 GNUNET_IDENTITY_ego_get_anonymous ()
176 static struct GNUNET_IDENTITY_Ego anon;
177 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
181 anon.pk = (struct GNUNET_CRYPTO_EcdsaPrivateKey *) GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
182 GNUNET_CRYPTO_ecdsa_key_get_public (anon.pk,
184 GNUNET_CRYPTO_hash (&pub,
192 * Try again to connect to the identity service.
194 * @param cls handle to the identity service.
197 reconnect (void *cls);
201 * Free ego from hash map.
203 * @param cls identity service handle
205 * @param value ego to free
206 * @return #GNUNET_OK (continue to iterate)
210 const struct GNUNET_HashCode *key,
213 struct GNUNET_IDENTITY_Handle *h = cls;
214 struct GNUNET_IDENTITY_Ego *ego = value;
221 GNUNET_free (ego->pk);
222 GNUNET_free (ego->name);
223 GNUNET_assert (GNUNET_YES ==
224 GNUNET_CONTAINER_multihashmap_remove (h->egos,
233 * Reschedule a connect attempt to the service.
235 * @param h transport service to reconnect
238 reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
240 struct GNUNET_IDENTITY_Operation *op;
242 GNUNET_assert (NULL == h->reconnect_task);
246 GNUNET_MQ_destroy (h->mq);
249 while (NULL != (op = h->op_head))
251 GNUNET_CONTAINER_DLL_remove (h->op_head,
254 if (NULL != op->cont)
256 "Error in communication with the identity service");
257 else if (NULL != op->cb)
264 GNUNET_CONTAINER_multihashmap_iterate (h->egos,
267 LOG (GNUNET_ERROR_TYPE_DEBUG,
268 "Scheduling task to reconnect to identity service in %s.\n",
269 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay,
272 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
275 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
280 * Generic error handler, called with the appropriate error code and
281 * the same closure specified at the creation of the message queue.
282 * Not every message queue implementation supports an error handler.
284 * @param cls closure with the `struct GNUNET_IDENTITY_Handle *`
285 * @param error error code
288 mq_error_handler (void *cls,
289 enum GNUNET_MQ_Error error)
291 struct GNUNET_IDENTITY_Handle *h = cls;
293 reschedule_connect (h);
298 * We received a result code from the service. Check the message
302 * @param rcm result message received
303 * @return #GNUNET_OK if the message is well-formed
306 check_identity_result_code (void *cls,
307 const struct ResultCodeMessage *rcm)
309 uint16_t size = ntohs (rcm->header.size) - sizeof (*rcm);
310 const char *str = (const char *) &rcm[1];
314 if ('\0' != str[size - 1])
317 return GNUNET_SYSERR;
324 * We received a result code from the service.
327 * @param rcm result message received
330 handle_identity_result_code (void *cls,
331 const struct ResultCodeMessage *rcm)
333 struct GNUNET_IDENTITY_Handle *h = cls;
334 struct GNUNET_IDENTITY_Operation *op;
335 uint16_t size = ntohs (rcm->header.size) - sizeof (*rcm);
336 const char *str = (0 == size) ? NULL : (const char *) &rcm[1];
342 reschedule_connect (h);
345 GNUNET_CONTAINER_DLL_remove (h->op_head,
348 if (NULL != op->cont)
351 else if (NULL != op->cb)
352 op->cb (op->cls, NULL, NULL, NULL);
358 * Check validity of identity update message.
361 * @param um message received
362 * @return #GNUNET_OK if the message is well-formed
365 check_identity_update (void *cls,
366 const struct UpdateMessage *um)
368 uint16_t size = ntohs (um->header.size);
369 uint16_t name_len = ntohs (um->name_len);
370 const char *str = (const char *) &um[1];
372 if ( (size != name_len + sizeof (struct UpdateMessage)) ||
374 ('\0' != str[name_len - 1])) )
377 return GNUNET_SYSERR;
384 * Handle identity update message.
387 * @param um message received
390 handle_identity_update (void *cls,
391 const struct UpdateMessage *um)
393 struct GNUNET_IDENTITY_Handle *h = cls;
394 uint16_t name_len = ntohs (um->name_len);
395 const char *str = (0 == name_len) ? NULL : (const char *) &um[1];
396 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
397 struct GNUNET_HashCode id;
398 struct GNUNET_IDENTITY_Ego *ego;
400 if (GNUNET_YES == ntohs (um->end_of_list))
402 /* end of initial list of data */
410 GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key,
412 GNUNET_CRYPTO_hash (&pub,
415 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
419 /* ego was created */
422 /* deletion of unknown ego? not allowed */
424 reschedule_connect (h);
427 ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
428 ego->pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
429 *ego->pk = um->private_key;
430 ego->name = GNUNET_strdup (str);
432 GNUNET_assert (GNUNET_YES ==
433 GNUNET_CONTAINER_multihashmap_put (h->egos,
436 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
440 /* ego was deleted */
441 GNUNET_assert (GNUNET_YES ==
442 GNUNET_CONTAINER_multihashmap_remove (h->egos,
448 /* ego changed name */
449 GNUNET_free (ego->name);
450 ego->name = GNUNET_strdup (str);
452 /* inform application about change */
458 /* complete deletion */
461 GNUNET_free (ego->pk);
462 GNUNET_free (ego->name);
469 * Function called when we receive a set default message from the
473 * @param sdm message received
474 * @return #GNUNET_OK if the message is well-formed
477 check_identity_set_default (void *cls,
478 const struct SetDefaultMessage *sdm)
480 uint16_t size = ntohs (sdm->header.size) - sizeof (*sdm);
481 uint16_t name_len = ntohs (sdm->name_len);
482 const char *str = (const char *) &sdm[1];
484 if ( (size != name_len) ||
486 ('\0' != str[name_len - 1]) ) )
489 return GNUNET_SYSERR;
491 GNUNET_break (0 == ntohs (sdm->reserved));
497 * Type of a function to call when we receive a message
501 * @param sdm message received
504 handle_identity_set_default (void *cls,
505 const struct SetDefaultMessage *sdm)
507 struct GNUNET_IDENTITY_Handle *h = cls;
508 struct GNUNET_IDENTITY_Operation *op;
509 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
510 struct GNUNET_HashCode id;
511 struct GNUNET_IDENTITY_Ego *ego;
513 GNUNET_CRYPTO_ecdsa_key_get_public (&sdm->private_key,
515 GNUNET_CRYPTO_hash (&pub,
518 ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
523 reschedule_connect (h);
530 reschedule_connect (h);
533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
534 "Received SET_DEFAULT message from identity service\n");
535 GNUNET_CONTAINER_DLL_remove (h->op_head,
548 * Try again to connect to the identity service.
550 * @param cls handle to the identity service.
553 reconnect (void *cls)
555 struct GNUNET_IDENTITY_Handle *h = cls;
556 struct GNUNET_MQ_MessageHandler handlers[] = {
557 GNUNET_MQ_hd_var_size (identity_result_code,
558 GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
559 struct ResultCodeMessage,
561 GNUNET_MQ_hd_var_size (identity_update,
562 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
563 struct UpdateMessage,
565 GNUNET_MQ_hd_var_size (identity_set_default,
566 GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT,
567 struct SetDefaultMessage,
569 GNUNET_MQ_handler_end ()
571 struct GNUNET_MQ_Envelope *env;
572 struct GNUNET_MessageHeader *msg;
574 h->reconnect_task = NULL;
575 LOG (GNUNET_ERROR_TYPE_DEBUG,
576 "Connecting to identity service.\n");
577 GNUNET_assert (NULL == h->mq);
578 h->mq = GNUNET_CLIENT_connecT (h->cfg,
585 env = GNUNET_MQ_msg (msg,
586 GNUNET_MESSAGE_TYPE_IDENTITY_START);
587 GNUNET_MQ_send (h->mq,
593 * Connect to the identity service.
595 * @param cfg the configuration to use
596 * @param cb function to call on all identity events, can be NULL
597 * @param cb_cls closure for @a cb
598 * @return handle to use
600 struct GNUNET_IDENTITY_Handle *
601 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
602 GNUNET_IDENTITY_Callback cb,
605 struct GNUNET_IDENTITY_Handle *h;
607 h = GNUNET_new (struct GNUNET_IDENTITY_Handle);
611 h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
623 * Obtain the ECC key associated with a ego.
626 * @return associated ECC key, valid as long as the ego is valid
628 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
629 GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
636 * Get the identifier (public key) of an ego.
638 * @param ego identity handle with the private key
639 * @param pk set to ego's public key
642 GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
643 struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
645 GNUNET_CRYPTO_ecdsa_key_get_public (ego->pk,
651 * Obtain the identity that is currently preferred/default
654 * @param h identity service to query
655 * @param service_name for which service is an identity wanted
656 * @param cb function to call with the result (will only be called once)
657 * @param cb_cls closure for @a cb
658 * @return handle to abort the operation
660 struct GNUNET_IDENTITY_Operation *
661 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *h,
662 const char *service_name,
663 GNUNET_IDENTITY_Callback cb,
666 struct GNUNET_IDENTITY_Operation *op;
667 struct GNUNET_MQ_Envelope *env;
668 struct GetDefaultMessage *gdm;
673 slen = strlen (service_name) + 1;
674 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct GetDefaultMessage))
679 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
683 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
686 env = GNUNET_MQ_msg_extra (gdm,
688 GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT);
689 gdm->name_len = htons (slen);
690 gdm->reserved = htons (0);
691 GNUNET_memcpy (&gdm[1],
694 GNUNET_MQ_send (h->mq,
701 * Set the preferred/default identity for a service.
703 * @param h identity service to inform
704 * @param service_name for which service is an identity set
705 * @param ego new default identity to be set for this service
706 * @param cont function to call once the operation finished
707 * @param cont_cls closure for @a cont
708 * @return handle to abort the operation
710 struct GNUNET_IDENTITY_Operation *
711 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *h,
712 const char *service_name,
713 struct GNUNET_IDENTITY_Ego *ego,
714 GNUNET_IDENTITY_Continuation cont,
717 struct GNUNET_IDENTITY_Operation *op;
718 struct GNUNET_MQ_Envelope *env;
719 struct SetDefaultMessage *sdm;
724 slen = strlen (service_name) + 1;
725 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct SetDefaultMessage))
730 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
734 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
737 env = GNUNET_MQ_msg_extra (sdm,
739 GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
740 sdm->name_len = htons (slen);
741 sdm->reserved = htons (0);
742 sdm->private_key = *ego->pk;
743 GNUNET_memcpy (&sdm[1],
746 GNUNET_MQ_send (h->mq,
753 * Create a new identity with the given name.
755 * @param h identity service to use
756 * @param name desired name
757 * @param cont function to call with the result (will only be called once)
758 * @param cont_cls closure for @a cont
759 * @return handle to abort the operation
761 struct GNUNET_IDENTITY_Operation *
762 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
764 GNUNET_IDENTITY_Continuation cont,
767 struct GNUNET_IDENTITY_Operation *op;
768 struct GNUNET_MQ_Envelope *env;
769 struct CreateRequestMessage *crm;
770 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
775 slen = strlen (name) + 1;
776 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct CreateRequestMessage))
781 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
785 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
788 env = GNUNET_MQ_msg_extra (crm,
790 GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
791 crm->name_len = htons (slen);
792 crm->reserved = htons (0);
793 pk = GNUNET_CRYPTO_ecdsa_key_create ();
794 crm->private_key = *pk;
796 GNUNET_memcpy (&crm[1],
799 GNUNET_MQ_send (h->mq,
806 * Renames an existing identity.
808 * @param h identity service to use
809 * @param old_name old name
810 * @param new_name desired new name
811 * @param cb function to call with the result (will only be called once)
812 * @param cb_cls closure for @a cb
813 * @return handle to abort the operation
815 struct GNUNET_IDENTITY_Operation *
816 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
817 const char *old_name,
818 const char *new_name,
819 GNUNET_IDENTITY_Continuation cb,
822 struct GNUNET_IDENTITY_Operation *op;
823 struct GNUNET_MQ_Envelope *env;
824 struct RenameMessage *grm;
831 slen_old = strlen (old_name) + 1;
832 slen_new = strlen (new_name) + 1;
833 if ( (slen_old >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
834 (slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE) ||
835 (slen_old + slen_new >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct RenameMessage)) )
840 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
844 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
847 env = GNUNET_MQ_msg_extra (grm,
849 GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
850 grm->old_name_len = htons (slen_old);
851 grm->new_name_len = htons (slen_new);
852 dst = (char *) &grm[1];
856 GNUNET_memcpy (&dst[slen_old],
859 GNUNET_MQ_send (h->mq,
866 * Delete an existing identity.
868 * @param h identity service to use
869 * @param name name of the identity to delete
870 * @param cb function to call with the result (will only be called once)
871 * @param cb_cls closure for @a cb
872 * @return handle to abort the operation
874 struct GNUNET_IDENTITY_Operation *
875 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
877 GNUNET_IDENTITY_Continuation cb,
880 struct GNUNET_IDENTITY_Operation *op;
881 struct GNUNET_MQ_Envelope *env;
882 struct DeleteMessage *gdm;
887 slen = strlen (name) + 1;
888 if (slen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct DeleteMessage))
893 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
897 GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
900 env = GNUNET_MQ_msg_extra (gdm,
902 GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
903 gdm->name_len = htons (slen);
904 gdm->reserved = htons (0);
905 GNUNET_memcpy (&gdm[1],
908 GNUNET_MQ_send (h->mq,
915 * Cancel an identity operation. Note that the operation MAY still
916 * be executed; this merely cancels the continuation; if the request
917 * was already transmitted, the service may still choose to complete
920 * @param op operation to cancel
923 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
931 * Disconnect from identity service
933 * @param h handle to destroy
936 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
938 struct GNUNET_IDENTITY_Operation *op;
940 GNUNET_assert (NULL != h);
941 if (h->reconnect_task != NULL)
943 GNUNET_SCHEDULER_cancel (h->reconnect_task);
944 h->reconnect_task = NULL;
948 GNUNET_CONTAINER_multihashmap_iterate (h->egos,
951 GNUNET_CONTAINER_multihashmap_destroy (h->egos);
954 while (NULL != (op = h->op_head))
956 GNUNET_break (NULL == op->cont);
957 GNUNET_CONTAINER_DLL_remove (h->op_head,
964 GNUNET_MQ_destroy (h->mq);
970 /* end of identity_api.c */