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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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__)
37 * Handle for an operation with the identity service.
39 struct GNUNET_IDENTITY_Operation
42 * Main identity handle.
44 struct GNUNET_IDENTITY_Handle *h;
47 * We keep operations in a DLL.
49 struct GNUNET_IDENTITY_Operation *next;
52 * We keep operations in a DLL.
54 struct GNUNET_IDENTITY_Operation *prev;
57 * Message to send to the identity service.
58 * Allocated at the end of this struct.
60 const struct GNUNET_MessageHeader *msg;
63 * Continuation to invoke with the result of the transmission; @e cb
64 * and @e create_cont will be NULL in this case.
66 GNUNET_IDENTITY_Continuation cont;
69 * Continuation to invoke with the result of the transmission; @e cb
70 * and @a cb will be NULL in this case.
72 GNUNET_IDENTITY_CreateContinuation create_cont;
75 * Private key to return to @e create_cont, or NULL.
77 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
80 * Continuation to invoke with the result of the transmission for
81 * 'get' operations (@e cont and @a create_cont will be NULL in this case).
83 GNUNET_IDENTITY_Callback cb;
86 * Closure for @e cont or @e cb.
93 * Handle for the service.
95 struct GNUNET_IDENTITY_Handle
98 * Configuration to use.
100 const struct GNUNET_CONFIGURATION_Handle *cfg;
103 * Connection to service.
105 struct GNUNET_MQ_Handle *mq;
108 * Hash map from the hash of the public key to the
109 * respective `GNUNET_IDENTITY_Ego` handle.
111 struct GNUNET_CONTAINER_MultiHashMap *egos;
114 * Function to call when we receive updates.
116 GNUNET_IDENTITY_Callback cb;
124 * Head of active operations.
126 struct GNUNET_IDENTITY_Operation *op_head;
129 * Tail of active operations.
131 struct GNUNET_IDENTITY_Operation *op_tail;
134 * Task doing exponential back-off trying to reconnect.
136 struct GNUNET_SCHEDULER_Task *reconnect_task;
139 * Time for next connect retry.
141 struct GNUNET_TIME_Relative reconnect_delay;
144 * Are we polling for incoming messages right now?
151 * Obtain the ego representing 'anonymous' users.
153 * @return handle for the anonymous user, must not be freed
155 const struct GNUNET_IDENTITY_Ego *
156 GNUNET_IDENTITY_ego_get_anonymous ()
158 static struct GNUNET_IDENTITY_Ego anon;
159 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
163 anon.pk = (struct GNUNET_CRYPTO_EcdsaPrivateKey *)
164 GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
165 GNUNET_CRYPTO_ecdsa_key_get_public (anon.pk, &pub);
166 GNUNET_CRYPTO_hash (&pub, sizeof(pub), &anon.id);
172 * Try again to connect to the identity service.
174 * @param cls handle to the identity service.
177 reconnect (void *cls);
181 * Free ego from hash map.
183 * @param cls identity service handle
185 * @param value ego to free
186 * @return #GNUNET_OK (continue to iterate)
189 free_ego (void *cls, const struct GNUNET_HashCode *key, void *value)
191 struct GNUNET_IDENTITY_Handle *h = cls;
192 struct GNUNET_IDENTITY_Ego *ego = value;
195 h->cb (h->cb_cls, ego, &ego->ctx, NULL);
196 GNUNET_free (ego->pk);
197 GNUNET_free (ego->name);
198 GNUNET_assert (GNUNET_YES ==
199 GNUNET_CONTAINER_multihashmap_remove (h->egos, key, value));
206 * Reschedule a connect attempt to the service.
208 * @param h transport service to reconnect
211 reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
213 struct GNUNET_IDENTITY_Operation *op;
215 GNUNET_assert (NULL == h->reconnect_task);
219 GNUNET_MQ_destroy (h->mq);
222 while (NULL != (op = h->op_head))
224 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
225 if (NULL != op->cont)
226 op->cont (op->cls, "Error in communication with the identity service");
227 else if (NULL != op->cb)
228 op->cb (op->cls, NULL, NULL, NULL);
229 else if (NULL != op->create_cont)
230 op->create_cont (op->cls,
232 "Failed to communicate with the identity service");
233 GNUNET_free_non_null (op->pk);
236 GNUNET_CONTAINER_multihashmap_iterate (h->egos, &free_ego, h);
237 LOG (GNUNET_ERROR_TYPE_DEBUG,
238 "Scheduling task to reconnect to identity service in %s.\n",
239 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
241 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
242 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
247 * Generic error handler, called with the appropriate error code and
248 * the same closure specified at the creation of the message queue.
249 * Not every message queue implementation supports an error handler.
251 * @param cls closure with the `struct GNUNET_IDENTITY_Handle *`
252 * @param error error code
255 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
257 struct GNUNET_IDENTITY_Handle *h = cls;
259 reschedule_connect (h);
264 * We received a result code from the service. Check the message
268 * @param rcm result message received
269 * @return #GNUNET_OK if the message is well-formed
272 check_identity_result_code (void *cls, const struct ResultCodeMessage *rcm)
274 if (sizeof(*rcm) != htons (rcm->header.size))
275 GNUNET_MQ_check_zero_termination (rcm);
281 * We received a result code from the service.
284 * @param rcm result message received
287 handle_identity_result_code (void *cls, const struct ResultCodeMessage *rcm)
289 struct GNUNET_IDENTITY_Handle *h = cls;
290 struct GNUNET_IDENTITY_Operation *op;
291 uint16_t size = ntohs (rcm->header.size) - sizeof(*rcm);
292 const char *str = (0 == size) ? NULL : (const char *) &rcm[1];
298 reschedule_connect (h);
301 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
302 if (NULL != op->cont)
303 op->cont (op->cls, str);
304 else if (NULL != op->cb)
305 op->cb (op->cls, NULL, NULL, NULL);
306 else if (NULL != op->create_cont)
307 op->create_cont (op->cls, (NULL == str) ? op->pk : NULL, str);
308 GNUNET_free_non_null (op->pk);
314 * Check validity of identity update message.
317 * @param um message received
318 * @return #GNUNET_OK if the message is well-formed
321 check_identity_update (void *cls, const struct UpdateMessage *um)
323 uint16_t size = ntohs (um->header.size);
324 uint16_t name_len = ntohs (um->name_len);
325 const char *str = (const char *) &um[1];
327 if ((size != name_len + sizeof(struct UpdateMessage)) ||
328 ((0 != name_len) && ('\0' != str[name_len - 1])))
331 return GNUNET_SYSERR;
338 * Handle identity update message.
341 * @param um message received
344 handle_identity_update (void *cls, const struct UpdateMessage *um)
346 struct GNUNET_IDENTITY_Handle *h = cls;
347 uint16_t name_len = ntohs (um->name_len);
348 const char *str = (0 == name_len) ? NULL : (const char *) &um[1];
349 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
350 struct GNUNET_HashCode id;
351 struct GNUNET_IDENTITY_Ego *ego;
353 if (GNUNET_YES == ntohs (um->end_of_list))
355 /* end of initial list of data */
357 h->cb (h->cb_cls, NULL, NULL, NULL);
360 GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key, &pub);
361 GNUNET_CRYPTO_hash (&pub, sizeof(pub), &id);
362 ego = GNUNET_CONTAINER_multihashmap_get (h->egos, &id);
365 /* ego was created */
368 /* deletion of unknown ego? not allowed */
370 reschedule_connect (h);
373 ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
374 ego->pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
375 *ego->pk = um->private_key;
376 ego->name = GNUNET_strdup (str);
378 GNUNET_assert (GNUNET_YES ==
379 GNUNET_CONTAINER_multihashmap_put (
383 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
387 /* ego was deleted */
388 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (h->egos,
394 /* ego changed name */
395 GNUNET_free (ego->name);
396 ego->name = GNUNET_strdup (str);
398 /* inform application about change */
400 h->cb (h->cb_cls, ego, &ego->ctx, str);
401 /* complete deletion */
404 GNUNET_free (ego->pk);
405 GNUNET_free (ego->name);
412 * Function called when we receive a set default message from the
416 * @param sdm message received
417 * @return #GNUNET_OK if the message is well-formed
420 check_identity_set_default (void *cls, const struct SetDefaultMessage *sdm)
422 uint16_t size = ntohs (sdm->header.size) - sizeof(*sdm);
423 uint16_t name_len = ntohs (sdm->name_len);
424 const char *str = (const char *) &sdm[1];
426 if ((size != name_len) || ((0 != name_len) && ('\0' != str[name_len - 1])))
429 return GNUNET_SYSERR;
431 GNUNET_break (0 == ntohs (sdm->reserved));
437 * Type of a function to call when we receive a message
441 * @param sdm message received
444 handle_identity_set_default (void *cls, const struct SetDefaultMessage *sdm)
446 struct GNUNET_IDENTITY_Handle *h = cls;
447 struct GNUNET_IDENTITY_Operation *op;
448 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
449 struct GNUNET_HashCode id;
450 struct GNUNET_IDENTITY_Ego *ego;
452 GNUNET_CRYPTO_ecdsa_key_get_public (&sdm->private_key, &pub);
453 GNUNET_CRYPTO_hash (&pub, sizeof(pub), &id);
454 ego = GNUNET_CONTAINER_multihashmap_get (h->egos, &id);
458 reschedule_connect (h);
465 reschedule_connect (h);
468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
469 "Received SET_DEFAULT message from identity service\n");
470 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
472 op->cb (op->cls, ego, &ego->ctx, ego->name);
478 * Try again to connect to the identity service.
480 * @param cls handle to the identity service.
483 reconnect (void *cls)
485 struct GNUNET_IDENTITY_Handle *h = cls;
486 struct GNUNET_MQ_MessageHandler handlers[] =
487 { GNUNET_MQ_hd_var_size (identity_result_code,
488 GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
489 struct ResultCodeMessage,
491 GNUNET_MQ_hd_var_size (identity_update,
492 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
493 struct UpdateMessage,
495 GNUNET_MQ_hd_var_size (identity_set_default,
496 GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT,
497 struct SetDefaultMessage,
499 GNUNET_MQ_handler_end () };
500 struct GNUNET_MQ_Envelope *env;
501 struct GNUNET_MessageHeader *msg;
503 h->reconnect_task = NULL;
504 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to identity service.\n");
505 GNUNET_assert (NULL == h->mq);
507 GNUNET_CLIENT_connect (h->cfg, "identity", handlers, &mq_error_handler, h);
512 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_IDENTITY_START);
513 GNUNET_MQ_send (h->mq, env);
519 * Connect to the identity service.
521 * @param cfg the configuration to use
522 * @param cb function to call on all identity events, can be NULL
523 * @param cb_cls closure for @a cb
524 * @return handle to use
526 struct GNUNET_IDENTITY_Handle *
527 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
528 GNUNET_IDENTITY_Callback cb,
531 struct GNUNET_IDENTITY_Handle *h;
533 h = GNUNET_new (struct GNUNET_IDENTITY_Handle);
537 h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
549 * Obtain the ECC key associated with a ego.
552 * @return associated ECC key, valid as long as the ego is valid
554 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
555 GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
562 * Get the identifier (public key) of an ego.
564 * @param ego identity handle with the private key
565 * @param pk set to ego's public key
568 GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
569 struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
571 GNUNET_CRYPTO_ecdsa_key_get_public (ego->pk, pk);
576 * Obtain the identity that is currently preferred/default
579 * @param h identity service to query
580 * @param service_name for which service is an identity wanted
581 * @param cb function to call with the result (will only be called once)
582 * @param cb_cls closure for @a cb
583 * @return handle to abort the operation
585 struct GNUNET_IDENTITY_Operation *
586 GNUNET_IDENTITY_get (struct GNUNET_IDENTITY_Handle *h,
587 const char *service_name,
588 GNUNET_IDENTITY_Callback cb,
591 struct GNUNET_IDENTITY_Operation *op;
592 struct GNUNET_MQ_Envelope *env;
593 struct GetDefaultMessage *gdm;
598 GNUNET_assert (NULL != h->cb);
599 slen = strlen (service_name) + 1;
600 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct GetDefaultMessage))
605 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
609 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
611 GNUNET_MQ_msg_extra (gdm, slen, GNUNET_MESSAGE_TYPE_IDENTITY_GET_DEFAULT);
612 gdm->name_len = htons (slen);
613 gdm->reserved = htons (0);
614 GNUNET_memcpy (&gdm[1], service_name, slen);
615 GNUNET_MQ_send (h->mq, env);
621 * Set the preferred/default identity for a service.
623 * @param h identity service to inform
624 * @param service_name for which service is an identity set
625 * @param ego new default identity to be set for this service
626 * @param cont function to call once the operation finished
627 * @param cont_cls closure for @a cont
628 * @return handle to abort the operation
630 struct GNUNET_IDENTITY_Operation *
631 GNUNET_IDENTITY_set (struct GNUNET_IDENTITY_Handle *h,
632 const char *service_name,
633 struct GNUNET_IDENTITY_Ego *ego,
634 GNUNET_IDENTITY_Continuation cont,
637 struct GNUNET_IDENTITY_Operation *op;
638 struct GNUNET_MQ_Envelope *env;
639 struct SetDefaultMessage *sdm;
644 GNUNET_assert (NULL != h->cb);
645 slen = strlen (service_name) + 1;
646 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct SetDefaultMessage))
651 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
655 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
657 GNUNET_MQ_msg_extra (sdm, slen, GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
658 sdm->name_len = htons (slen);
659 sdm->reserved = htons (0);
660 sdm->private_key = *ego->pk;
661 GNUNET_memcpy (&sdm[1], service_name, slen);
662 GNUNET_MQ_send (h->mq, env);
668 * Create a new identity with the given name.
670 * @param h identity service to use
671 * @param name desired name
672 * @param cont function to call with the result (will only be called once)
673 * @param cont_cls closure for @a cont
674 * @return handle to abort the operation
676 struct GNUNET_IDENTITY_Operation *
677 GNUNET_IDENTITY_create (struct GNUNET_IDENTITY_Handle *h,
679 GNUNET_IDENTITY_CreateContinuation cont,
682 struct GNUNET_IDENTITY_Operation *op;
683 struct GNUNET_MQ_Envelope *env;
684 struct CreateRequestMessage *crm;
685 struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
690 slen = strlen (name) + 1;
691 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct CreateRequestMessage))
696 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
698 op->create_cont = cont;
700 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
701 env = GNUNET_MQ_msg_extra (crm, slen, GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
702 crm->name_len = htons (slen);
703 crm->reserved = htons (0);
704 pk = GNUNET_CRYPTO_ecdsa_key_create ();
705 crm->private_key = *pk;
707 GNUNET_memcpy (&crm[1], name, slen);
708 GNUNET_MQ_send (h->mq, env);
714 * Renames an existing identity.
716 * @param h identity service to use
717 * @param old_name old name
718 * @param new_name desired new name
719 * @param cb function to call with the result (will only be called once)
720 * @param cb_cls closure for @a cb
721 * @return handle to abort the operation
723 struct GNUNET_IDENTITY_Operation *
724 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
725 const char *old_name,
726 const char *new_name,
727 GNUNET_IDENTITY_Continuation cb,
730 struct GNUNET_IDENTITY_Operation *op;
731 struct GNUNET_MQ_Envelope *env;
732 struct RenameMessage *grm;
739 slen_old = strlen (old_name) + 1;
740 slen_new = strlen (new_name) + 1;
741 if ((slen_old >= GNUNET_MAX_MESSAGE_SIZE) ||
742 (slen_new >= GNUNET_MAX_MESSAGE_SIZE) ||
743 (slen_old + slen_new >=
744 GNUNET_MAX_MESSAGE_SIZE - sizeof(struct RenameMessage)))
749 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
753 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
754 env = GNUNET_MQ_msg_extra (grm,
756 GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
757 grm->old_name_len = htons (slen_old);
758 grm->new_name_len = htons (slen_new);
759 dst = (char *) &grm[1];
760 GNUNET_memcpy (dst, old_name, slen_old);
761 GNUNET_memcpy (&dst[slen_old], new_name, slen_new);
762 GNUNET_MQ_send (h->mq, env);
768 * Delete an existing identity.
770 * @param h identity service to use
771 * @param name name of the identity to delete
772 * @param cb function to call with the result (will only be called once)
773 * @param cb_cls closure for @a cb
774 * @return handle to abort the operation
776 struct GNUNET_IDENTITY_Operation *
777 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
779 GNUNET_IDENTITY_Continuation cb,
782 struct GNUNET_IDENTITY_Operation *op;
783 struct GNUNET_MQ_Envelope *env;
784 struct DeleteMessage *gdm;
789 slen = strlen (name) + 1;
790 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct DeleteMessage))
795 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
799 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
800 env = GNUNET_MQ_msg_extra (gdm, slen, GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
801 gdm->name_len = htons (slen);
802 gdm->reserved = htons (0);
803 GNUNET_memcpy (&gdm[1], name, slen);
804 GNUNET_MQ_send (h->mq, env);
810 * Cancel an identity operation. Note that the operation MAY still
811 * be executed; this merely cancels the continuation; if the request
812 * was already transmitted, the service may still choose to complete
815 * @param op operation to cancel
818 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
822 op->create_cont = NULL;
825 GNUNET_free (op->pk);
832 * Disconnect from identity service
834 * @param h handle to destroy
837 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
839 struct GNUNET_IDENTITY_Operation *op;
841 GNUNET_assert (NULL != h);
842 if (h->reconnect_task != NULL)
844 GNUNET_SCHEDULER_cancel (h->reconnect_task);
845 h->reconnect_task = NULL;
849 GNUNET_CONTAINER_multihashmap_iterate (h->egos, &free_ego, h);
850 GNUNET_CONTAINER_multihashmap_destroy (h->egos);
853 while (NULL != (op = h->op_head))
855 GNUNET_break (NULL == op->cont);
856 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
857 GNUNET_free_non_null (op->pk);
862 GNUNET_MQ_destroy (h->mq);
869 /* end of identity_api.c */