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;
160 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
164 anon.pk = *GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
165 GNUNET_CRYPTO_ecdsa_key_get_public (&anon.pk,
167 GNUNET_CRYPTO_hash (&pub,
176 * Try again to connect to the identity service.
178 * @param cls handle to the identity service.
181 reconnect (void *cls);
185 * Free ego from hash map.
187 * @param cls identity service handle
189 * @param value ego to free
190 * @return #GNUNET_OK (continue to iterate)
193 free_ego (void *cls, const struct GNUNET_HashCode *key, void *value)
195 struct GNUNET_IDENTITY_Handle *h = cls;
196 struct GNUNET_IDENTITY_Ego *ego = value;
199 h->cb (h->cb_cls, ego, &ego->ctx, NULL);
200 GNUNET_free (ego->name);
201 GNUNET_assert (GNUNET_YES ==
202 GNUNET_CONTAINER_multihashmap_remove (h->egos, key, value));
209 * Reschedule a connect attempt to the service.
211 * @param h transport service to reconnect
214 reschedule_connect (struct GNUNET_IDENTITY_Handle *h)
216 struct GNUNET_IDENTITY_Operation *op;
218 GNUNET_assert (NULL == h->reconnect_task);
222 GNUNET_MQ_destroy (h->mq);
225 while (NULL != (op = h->op_head))
227 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
228 if (NULL != op->cont)
229 op->cont (op->cls, "Error in communication with the identity service");
230 else if (NULL != op->cb)
231 op->cb (op->cls, NULL, NULL, NULL);
232 else if (NULL != op->create_cont)
233 op->create_cont (op->cls,
235 "Failed to communicate with the identity service");
238 GNUNET_CONTAINER_multihashmap_iterate (h->egos, &free_ego, h);
239 LOG (GNUNET_ERROR_TYPE_DEBUG,
240 "Scheduling task to reconnect to identity service in %s.\n",
241 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
243 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
244 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
249 * Generic error handler, called with the appropriate error code and
250 * the same closure specified at the creation of the message queue.
251 * Not every message queue implementation supports an error handler.
253 * @param cls closure with the `struct GNUNET_IDENTITY_Handle *`
254 * @param error error code
257 mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
259 struct GNUNET_IDENTITY_Handle *h = cls;
261 reschedule_connect (h);
266 * We received a result code from the service. Check the message
270 * @param rcm result message received
271 * @return #GNUNET_OK if the message is well-formed
274 check_identity_result_code (void *cls, const struct ResultCodeMessage *rcm)
276 if (sizeof(*rcm) != htons (rcm->header.size))
277 GNUNET_MQ_check_zero_termination (rcm);
283 * We received a result code from the service.
286 * @param rcm result message received
289 handle_identity_result_code (void *cls, const struct ResultCodeMessage *rcm)
291 struct GNUNET_IDENTITY_Handle *h = cls;
292 struct GNUNET_IDENTITY_Operation *op;
293 uint16_t size = ntohs (rcm->header.size) - sizeof(*rcm);
294 const char *str = (0 == size) ? NULL : (const char *) &rcm[1];
300 reschedule_connect (h);
303 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
304 if (NULL != op->cont)
305 op->cont (op->cls, str);
306 else if (NULL != op->cb)
307 op->cb (op->cls, NULL, NULL, NULL);
308 else if (NULL != op->create_cont)
309 op->create_cont (op->cls, (NULL == str) ? &op->pk : NULL, str);
315 * Check validity of identity update message.
318 * @param um message received
319 * @return #GNUNET_OK if the message is well-formed
322 check_identity_update (void *cls, const struct UpdateMessage *um)
324 uint16_t size = ntohs (um->header.size);
325 uint16_t name_len = ntohs (um->name_len);
326 const char *str = (const char *) &um[1];
328 if ((size != name_len + sizeof(struct UpdateMessage)) ||
329 ((0 != name_len) && ('\0' != str[name_len - 1])))
332 return GNUNET_SYSERR;
339 * Handle identity update message.
342 * @param um message received
345 handle_identity_update (void *cls, const struct UpdateMessage *um)
347 struct GNUNET_IDENTITY_Handle *h = cls;
348 uint16_t name_len = ntohs (um->name_len);
349 const char *str = (0 == name_len) ? NULL : (const char *) &um[1];
350 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
351 struct GNUNET_HashCode id;
352 struct GNUNET_IDENTITY_Ego *ego;
354 if (GNUNET_YES == ntohs (um->end_of_list))
356 /* end of initial list of data */
358 h->cb (h->cb_cls, NULL, NULL, NULL);
361 GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key, &pub);
362 GNUNET_CRYPTO_hash (&pub, sizeof(pub), &id);
363 ego = GNUNET_CONTAINER_multihashmap_get (h->egos, &id);
366 /* ego was created */
369 /* deletion of unknown ego? not allowed */
371 reschedule_connect (h);
374 ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
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->name);
411 * Function called when we receive a set default message from the
415 * @param sdm message received
416 * @return #GNUNET_OK if the message is well-formed
419 check_identity_set_default (void *cls, const struct SetDefaultMessage *sdm)
421 uint16_t size = ntohs (sdm->header.size) - sizeof(*sdm);
422 uint16_t name_len = ntohs (sdm->name_len);
423 const char *str = (const char *) &sdm[1];
425 if ((size != name_len) || ((0 != name_len) && ('\0' != str[name_len - 1])))
428 return GNUNET_SYSERR;
430 GNUNET_break (0 == ntohs (sdm->reserved));
436 * Type of a function to call when we receive a message
440 * @param sdm message received
443 handle_identity_set_default (void *cls, const struct SetDefaultMessage *sdm)
445 struct GNUNET_IDENTITY_Handle *h = cls;
446 struct GNUNET_IDENTITY_Operation *op;
447 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
448 struct GNUNET_HashCode id;
449 struct GNUNET_IDENTITY_Ego *ego;
451 GNUNET_CRYPTO_ecdsa_key_get_public (&sdm->private_key, &pub);
452 GNUNET_CRYPTO_hash (&pub, sizeof(pub), &id);
453 ego = GNUNET_CONTAINER_multihashmap_get (h->egos, &id);
457 reschedule_connect (h);
464 reschedule_connect (h);
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
468 "Received SET_DEFAULT message from identity service\n");
469 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
471 op->cb (op->cls, ego, &ego->ctx, ego->name);
477 * Try again to connect to the identity service.
479 * @param cls handle to the identity service.
482 reconnect (void *cls)
484 struct GNUNET_IDENTITY_Handle *h = cls;
485 struct GNUNET_MQ_MessageHandler handlers[] =
486 { GNUNET_MQ_hd_var_size (identity_result_code,
487 GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE,
488 struct ResultCodeMessage,
490 GNUNET_MQ_hd_var_size (identity_update,
491 GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE,
492 struct UpdateMessage,
494 GNUNET_MQ_hd_var_size (identity_set_default,
495 GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT,
496 struct SetDefaultMessage,
498 GNUNET_MQ_handler_end () };
499 struct GNUNET_MQ_Envelope *env;
500 struct GNUNET_MessageHeader *msg;
502 h->reconnect_task = NULL;
503 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to identity service.\n");
504 GNUNET_assert (NULL == h->mq);
506 GNUNET_CLIENT_connect (h->cfg, "identity", handlers, &mq_error_handler, h);
511 env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_IDENTITY_START);
512 GNUNET_MQ_send (h->mq, env);
518 * Connect to the identity service.
520 * @param cfg the configuration to use
521 * @param cb function to call on all identity events, can be NULL
522 * @param cb_cls closure for @a cb
523 * @return handle to use
525 struct GNUNET_IDENTITY_Handle *
526 GNUNET_IDENTITY_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
527 GNUNET_IDENTITY_Callback cb,
530 struct GNUNET_IDENTITY_Handle *h;
532 h = GNUNET_new (struct GNUNET_IDENTITY_Handle);
536 h->egos = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_YES);
548 * Obtain the ECC key associated with a ego.
551 * @return associated ECC key, valid as long as the ego is valid
553 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
554 GNUNET_IDENTITY_ego_get_private_key (const struct GNUNET_IDENTITY_Ego *ego)
561 * Get the identifier (public key) of an ego.
563 * @param ego identity handle with the private key
564 * @param pk set to ego's public key
567 GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
568 struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
570 GNUNET_CRYPTO_ecdsa_key_get_public (&ego->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;
689 slen = strlen (name) + 1;
690 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct CreateRequestMessage))
695 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
697 op->create_cont = cont;
699 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
700 env = GNUNET_MQ_msg_extra (crm, slen, GNUNET_MESSAGE_TYPE_IDENTITY_CREATE);
701 crm->name_len = htons (slen);
702 crm->reserved = htons (0);
703 GNUNET_CRYPTO_ecdsa_key_create (&crm->private_key);
704 op->pk = crm->private_key;
705 GNUNET_memcpy (&crm[1], name, slen);
706 GNUNET_MQ_send (h->mq, env);
712 * Renames an existing identity.
714 * @param h identity service to use
715 * @param old_name old name
716 * @param new_name desired new name
717 * @param cb function to call with the result (will only be called once)
718 * @param cb_cls closure for @a cb
719 * @return handle to abort the operation
721 struct GNUNET_IDENTITY_Operation *
722 GNUNET_IDENTITY_rename (struct GNUNET_IDENTITY_Handle *h,
723 const char *old_name,
724 const char *new_name,
725 GNUNET_IDENTITY_Continuation cb,
728 struct GNUNET_IDENTITY_Operation *op;
729 struct GNUNET_MQ_Envelope *env;
730 struct RenameMessage *grm;
737 slen_old = strlen (old_name) + 1;
738 slen_new = strlen (new_name) + 1;
739 if ((slen_old >= GNUNET_MAX_MESSAGE_SIZE) ||
740 (slen_new >= GNUNET_MAX_MESSAGE_SIZE) ||
741 (slen_old + slen_new >=
742 GNUNET_MAX_MESSAGE_SIZE - sizeof(struct RenameMessage)))
747 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
751 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
752 env = GNUNET_MQ_msg_extra (grm,
754 GNUNET_MESSAGE_TYPE_IDENTITY_RENAME);
755 grm->old_name_len = htons (slen_old);
756 grm->new_name_len = htons (slen_new);
757 dst = (char *) &grm[1];
758 GNUNET_memcpy (dst, old_name, slen_old);
759 GNUNET_memcpy (&dst[slen_old], new_name, slen_new);
760 GNUNET_MQ_send (h->mq, env);
766 * Delete an existing identity.
768 * @param h identity service to use
769 * @param name name of the identity to delete
770 * @param cb function to call with the result (will only be called once)
771 * @param cb_cls closure for @a cb
772 * @return handle to abort the operation
774 struct GNUNET_IDENTITY_Operation *
775 GNUNET_IDENTITY_delete (struct GNUNET_IDENTITY_Handle *h,
777 GNUNET_IDENTITY_Continuation cb,
780 struct GNUNET_IDENTITY_Operation *op;
781 struct GNUNET_MQ_Envelope *env;
782 struct DeleteMessage *gdm;
787 slen = strlen (name) + 1;
788 if (slen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct DeleteMessage))
793 op = GNUNET_new (struct GNUNET_IDENTITY_Operation);
797 GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, op);
798 env = GNUNET_MQ_msg_extra (gdm, slen, GNUNET_MESSAGE_TYPE_IDENTITY_DELETE);
799 gdm->name_len = htons (slen);
800 gdm->reserved = htons (0);
801 GNUNET_memcpy (&gdm[1], name, slen);
802 GNUNET_MQ_send (h->mq, env);
808 * Cancel an identity operation. Note that the operation MAY still
809 * be executed; this merely cancels the continuation; if the request
810 * was already transmitted, the service may still choose to complete
813 * @param op operation to cancel
816 GNUNET_IDENTITY_cancel (struct GNUNET_IDENTITY_Operation *op)
820 op->create_cont = NULL;
828 * Disconnect from identity service
830 * @param h handle to destroy
833 GNUNET_IDENTITY_disconnect (struct GNUNET_IDENTITY_Handle *h)
835 struct GNUNET_IDENTITY_Operation *op;
837 GNUNET_assert (NULL != h);
838 if (h->reconnect_task != NULL)
840 GNUNET_SCHEDULER_cancel (h->reconnect_task);
841 h->reconnect_task = NULL;
845 GNUNET_CONTAINER_multihashmap_iterate (h->egos, &free_ego, h);
846 GNUNET_CONTAINER_multihashmap_destroy (h->egos);
849 while (NULL != (op = h->op_head))
851 GNUNET_break (NULL == op->cont);
852 GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, op);
860 GNUNET_MQ_destroy (h->mq);
867 /* end of identity_api.c */