2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 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 * @author Martin Schanzenbach
23 * @file src/reclaim/gnunet-service-reclaim_tickets.c
24 * @brief reclaim tickets
28 #include "gnunet-service-reclaim_tickets.h"
32 * FIXME: the defaul ticket iteration interval should probably
33 * be the minimim attribute expiration.
35 #define DEFAULT_TICKET_REFRESH_INTERVAL GNUNET_TIME_UNIT_HOURS
38 * Handle for a parallel GNS lookup job
39 * (Declaration further below)
41 struct ParallelLookup;
45 * A reference to a ticket stored in GNS
47 struct TicketReference
52 struct TicketReference *next;
57 struct TicketReference *prev;
62 struct GNUNET_RECLAIM_AttributeList *attrs;
67 struct GNUNET_RECLAIM_Ticket ticket;
72 * Handle to a consume operation
74 struct RECLAIM_TICKETS_ConsumeHandle
79 struct GNUNET_RECLAIM_Ticket ticket;
84 struct GNUNET_GNS_LookupRequest *lookup_request;
89 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
94 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
99 struct ParallelLookup *parallel_lookups_head;
104 struct ParallelLookup *parallel_lookups_tail;
109 struct GNUNET_SCHEDULER_Task *kill_task;
114 struct GNUNET_RECLAIM_AttributeList *attrs;
119 struct GNUNET_RECLAIM_AttestationList *attests;
124 struct GNUNET_TIME_Absolute lookup_start_time;
129 RECLAIM_TICKETS_ConsumeCallback cb;
139 * Handle for a parallel GNS lookup job
141 struct ParallelLookup
144 struct ParallelLookup *next;
147 struct ParallelLookup *prev;
149 /* The GNS request */
150 struct GNUNET_GNS_LookupRequest *lookup_request;
152 /* The handle the return to */
153 struct RECLAIM_TICKETS_ConsumeHandle *handle;
158 struct GNUNET_TIME_Absolute lookup_start_time;
160 /* The label to look up */
166 * Ticket issue request handle
168 struct TicketIssueHandle
171 * Attributes to issue
173 struct GNUNET_RECLAIM_AttributeList *attrs;
178 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
183 struct GNUNET_RECLAIM_Ticket ticket;
188 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
193 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
198 RECLAIM_TICKETS_TicketResult cb;
210 struct RECLAIM_TICKETS_Iterator
213 * Namestore queue entry
215 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
220 RECLAIM_TICKETS_TicketIter cb;
229 struct RevokedAttributeEntry
234 struct RevokedAttributeEntry *next;
239 struct RevokedAttributeEntry *prev;
242 * Old ID of the attribute
244 struct GNUNET_RECLAIM_Identifier old_id;
247 * New ID of the attribute
249 struct GNUNET_RECLAIM_Identifier new_id;
254 * Ticket revocation request handle
256 struct RECLAIM_TICKETS_RevokeHandle
261 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
266 RECLAIM_TICKETS_RevokeCallback cb;
276 struct GNUNET_RECLAIM_Ticket ticket;
281 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
286 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
291 struct RevokedAttributeEntry *attrs_head;
296 struct RevokedAttributeEntry *attrs_tail;
299 * Current attribute to move
301 struct RevokedAttributeEntry *move_attr;
304 * Number of attributes in ticket
306 unsigned int ticket_attrs;
311 struct TicketRecordsEntry *tickets_to_update_head;
316 struct TicketRecordsEntry *tickets_to_update_tail;
321 * Ticket expiration interval
323 static struct GNUNET_TIME_Relative ticket_refresh_interval;
326 /* Namestore handle */
327 static struct GNUNET_NAMESTORE_Handle *nsh;
331 static struct GNUNET_GNS_Handle *gns;
334 /* Handle to the statistics service */
335 static struct GNUNET_STATISTICS_Handle *stats;
339 * Cleanup revoke handle
341 * @param rh the ticket revocation handle
344 cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
346 struct RevokedAttributeEntry *ae;
347 struct TicketRecordsEntry *le;
349 if (NULL != rh->ns_qe)
350 GNUNET_NAMESTORE_cancel (rh->ns_qe);
351 if (NULL != rh->ns_it)
352 GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
353 while (NULL != (ae = rh->attrs_head))
355 GNUNET_CONTAINER_DLL_remove (rh->attrs_head, rh->attrs_tail, ae);
358 while (NULL != (le = rh->tickets_to_update_head))
360 GNUNET_CONTAINER_DLL_remove (rh->tickets_to_update_head,
361 rh->tickets_to_update_head,
363 if (NULL != le->data)
364 GNUNET_free (le->data);
365 if (NULL != le->label)
366 GNUNET_free (le->label);
374 * For each ticket, store new, updated attribute references
375 * (Implementation further below)
377 * @param cls handle to the operation
380 process_tickets (void *cls);
384 * Finished storing updated attribute references.
385 * Abort on error, else continue processing tickets
387 * @param cls handle to the operation
388 * @param success result of namestore operation
389 * @param emsg (NULL on success)
392 ticket_processed (void *cls, int32_t success, const char *emsg)
394 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
397 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
402 * For each ticket, store new, updated attribute references
404 * @param cls handle to the operation
407 process_tickets (void *cls)
409 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
410 struct TicketRecordsEntry *le;
411 struct RevokedAttributeEntry *ae;
413 if (NULL == rvk->tickets_to_update_head)
415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
416 "Finished updatding tickets, success\n");
417 rvk->cb (rvk->cb_cls, GNUNET_OK);
421 le = rvk->tickets_to_update_head;
422 GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
423 rvk->tickets_to_update_tail,
425 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
426 if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
431 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
432 "Unable to deserialize ticket record(s)\n");
433 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
437 for (int i = 0; i < le->rd_count; i++)
439 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
441 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
443 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(ae->old_id)))
445 rd[i].data = &ae->new_id;
448 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
455 GNUNET_free (le->label);
456 GNUNET_free (le->data);
462 * Done collecting tickets. Start processing.
464 * @param cls handle to the operation
467 rvk_ticket_update_finished (void *cls)
469 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
472 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
477 * We need to update all other tickets with the new attribute IDs.
478 * We first collect them all. Processing after.
480 * @param cls handle to the operation
481 * @param zone ticket issuer private key
482 * @param label ticket rnd
483 * @param rd_cound size of record set
484 * @param rd record set
487 rvk_ticket_update (void *cls,
488 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
490 unsigned int rd_count,
491 const struct GNUNET_GNSRECORD_Data *rd)
493 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
494 struct TicketRecordsEntry *le;
495 struct RevokedAttributeEntry *ae;
496 int has_changed = GNUNET_NO;
498 /** Let everything point to the old record **/
499 for (int i = 0; i < rd_count; i++)
501 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
503 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
505 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(ae->old_id)))
507 has_changed = GNUNET_YES;
510 if (GNUNET_YES == has_changed)
513 if (GNUNET_YES == has_changed)
515 le = GNUNET_new (struct TicketRecordsEntry);
516 le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
517 le->data = GNUNET_malloc (le->data_size);
518 le->rd_count = rd_count;
519 le->label = GNUNET_strdup (label);
520 GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
521 GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
522 rvk->tickets_to_update_tail,
525 GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
530 * Error iterating namestore. Abort.
532 * @param cls handle to the operation
535 rvk_ns_iter_err (void *cls)
537 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
540 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
546 * Error storing new attribute in namestore. Abort
548 * @param cls handle to the operation
551 rvk_ns_err (void *cls)
553 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
556 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
562 * We change every attribute ID of the ticket attributes we
564 * When we are done, we need to update any other ticket which
565 * included references to any of the changed attributes.
566 * (Implementation further below)
568 * @param rvk handle to the operation
571 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
575 * Delayed continuation for move_attrs
577 * @param cls handle to the operation.
580 move_attrs_cont (void *cls)
582 move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
587 * Done deleting the old record. Abort on error.
588 * Else, continue updating attribute IDs.
590 * @param cls handle to the operation
591 * @param success result of the namestore operation
592 * @param emsg error message (NULL on success)
595 del_attr_finished (void *cls, int32_t success, const char *emsg)
597 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
600 if (GNUNET_SYSERR == success)
602 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
603 "Error removing attribute: %s\n",
605 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
609 rvk->move_attr = rvk->move_attr->next;
610 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
615 * Updated an attribute ID.
616 * Abort on error if namestore operation failed.
617 * Else, we have to delete the old record.
619 * @param cls handle to the operation
620 * @param success result of the store operation
621 * @param emsg error message (NULL on success)
624 move_attr_finished (void *cls, int32_t success, const char *emsg)
626 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
630 if (GNUNET_SYSERR == success)
632 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
633 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
637 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
638 sizeof(rvk->move_attr->old_id));
639 GNUNET_assert (NULL != label);
640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
641 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
653 * Got the referenced attribute. Updating the ID
655 * @param cls handle to the operation
656 * @param zone issuer identity
657 * @param label attribute ID
658 * @param rd_count size of record set (should be 1)
659 * @param rd record set (the attribute)
662 rvk_move_attr_cb (void *cls,
663 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
665 unsigned int rd_count,
666 const struct GNUNET_GNSRECORD_Data *rd)
668 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
669 struct GNUNET_GNSRECORD_Data new_rd[rd_count];
670 struct RevokedAttributeEntry *le;
677 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
678 "The claim %s no longer exists!\n",
681 rvk->move_attr = le->next;
682 GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
684 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
687 GNUNET_RECLAIM_id_generate (&rvk->move_attr->new_id);
691 for (int i = 0; i < rd_count; i++)
693 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE == rd[i].record_type)
695 /** find a new place for this attribute **/
696 struct GNUNET_RECLAIM_Attribute *claim;
697 claim = GNUNET_RECLAIM_attribute_deserialize (rd[i].data,
699 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
700 "Attribute to update: Name=%s\n",
702 claim->id = rvk->move_attr->new_id;
703 new_rd[i].data_size = GNUNET_RECLAIM_attribute_serialize_get_size (claim);
704 attr_data = GNUNET_malloc (rd[i].data_size);
705 new_rd[i].data_size = GNUNET_RECLAIM_attribute_serialize (claim,
707 new_rd[i].data = attr_data;
708 new_rd[i].record_type = rd[i].record_type;
709 new_rd[i].flags = rd[i].flags;
710 new_rd[i].expiration_time = rd[i].expiration_time;
712 GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
713 sizeof (rvk->move_attr->new_id));
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
717 else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION == rd[i].record_type)
719 struct GNUNET_RECLAIM_Attestation *attest;
720 attest = GNUNET_RECLAIM_attestation_deserialize (rd[i].data,
722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723 "Attestation to update: Name=%s\n",
725 attest->id = rvk->move_attr->new_id;
726 new_rd[i].data_size =
727 GNUNET_RECLAIM_attestation_serialize_get_size (attest);
728 attr_data = GNUNET_malloc (rd[i].data_size);
729 new_rd[i].data_size = GNUNET_RECLAIM_attestation_serialize (attest,
731 new_rd[i].data = attr_data;
732 new_rd[i].record_type = rd[i].record_type;
733 new_rd[i].flags = rd[i].flags;
734 new_rd[i].expiration_time = rd[i].expiration_time;
736 GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
737 sizeof (rvk->move_attr->new_id));
738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation %s\n",
740 GNUNET_free (attest);
743 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
750 GNUNET_free (new_label);
751 GNUNET_free (attr_data);
756 * We change every attribute ID of the ticket attributes we
758 * When we are done, we need to update any other ticket which
759 * included references to any of the changed attributes.
761 * @param rvk handle to the operation
764 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
768 if (NULL == rvk->move_attr)
770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
772 GNUNET_NAMESTORE_zone_iteration_start (nsh,
778 &rvk_ticket_update_finished,
782 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
783 sizeof (rvk->move_attr->old_id));
784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving claim %s\n", label);
786 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
798 * Finished deleting ticket and attribute references.
800 * Else, we start changing every attribute ID in the
801 * found attribute references so that access is no longer
804 * @param cls handle to the operation
805 * @param success Namestore operation return value
806 * @param emsg error message (NULL on success)
809 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
811 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
814 if (GNUNET_SYSERR == success)
816 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
817 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
822 if (0 == rvk->ticket_attrs)
824 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
825 "No attributes to move... strange\n");
826 rvk->cb (rvk->cb_cls, GNUNET_OK);
830 rvk->move_attr = rvk->attrs_head;
836 * We found the attribute references.
837 * Store them for later and remove the record set.
839 * @param cls handle to the operation
840 * @param zone the issuer key
841 * @param label ticket rnd
842 * @param rd_cound size of record set
843 * @param rd record set
846 revoke_attrs_cb (void *cls,
847 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
849 unsigned int rd_count,
850 const struct GNUNET_GNSRECORD_Data *rd)
853 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
854 struct RevokedAttributeEntry *le;
858 * Temporarily store attribute references.
861 for (int i = 0; i < rd_count; i++)
863 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
865 le = GNUNET_new (struct RevokedAttributeEntry);
866 le->old_id = *((struct GNUNET_RECLAIM_Identifier *) rd[i].data);
867 GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
871 /** Remove attribute references **/
872 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
883 * Failed to query namestore. Abort operation
885 * @param cls handle to the operation
888 rvk_attrs_err_cb (void *cls)
890 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
892 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
899 * We start by looking up attribute references in order
900 * to change attribute IDs.
902 * @param ticket ticket to revoke
903 * @param identity private key of issuer
904 * @param cb revocation status callback
905 * @param cb_cls callback closure
906 * @return handle to the operation
908 struct RECLAIM_TICKETS_RevokeHandle *
909 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
910 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
911 RECLAIM_TICKETS_RevokeCallback cb,
914 struct RECLAIM_TICKETS_RevokeHandle *rvk;
917 rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
919 rvk->cb_cls = cb_cls;
920 rvk->identity = *identity;
921 rvk->ticket = *ticket;
922 GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
923 /** Get shared attributes **/
924 label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
925 sizeof(ticket->rnd));
926 GNUNET_assert (NULL != label);
927 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
940 * Cancel a revocation.
942 * @param rh handle to the operation
945 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
947 GNUNET_assert (NULL != rh);
952 /*******************************
954 *******************************/
957 * Cleanup ticket consume handle
959 * @param cth the handle to clean up
962 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
964 struct ParallelLookup *lu;
966 if (NULL != cth->lookup_request)
967 GNUNET_GNS_lookup_cancel (cth->lookup_request);
968 if (NULL != cth->kill_task)
969 GNUNET_SCHEDULER_cancel (cth->kill_task);
970 while (NULL != (lu = cth->parallel_lookups_head))
972 if (NULL != lu->lookup_request)
973 GNUNET_GNS_lookup_cancel (lu->lookup_request);
974 GNUNET_free_non_null (lu->label);
975 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
976 cth->parallel_lookups_tail,
981 if (NULL != cth->attrs)
982 GNUNET_RECLAIM_attribute_list_destroy (cth->attrs);
983 if (NULL != cth->attests)
984 GNUNET_RECLAIM_attestation_list_destroy (cth->attests);
990 * We found an attribute record.
992 * @param cls handle to the operation
993 * @param rd_cound size of record set
994 * @param rd record set
997 process_parallel_lookup_result (void *cls,
999 const struct GNUNET_GNSRECORD_Data *rd)
1001 struct ParallelLookup *parallel_lookup = cls;
1002 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
1003 struct GNUNET_RECLAIM_AttributeListEntry *attr_le;
1005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1006 "Parallel lookup finished (count=%u)\n",
1009 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1010 cth->parallel_lookups_tail,
1012 GNUNET_free (parallel_lookup->label);
1014 GNUNET_STATISTICS_update (stats,
1015 "attribute_lookup_time_total",
1016 GNUNET_TIME_absolute_get_duration (
1017 parallel_lookup->lookup_start_time)
1020 GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
1023 GNUNET_free (parallel_lookup);
1026 // REMARK: It is possible now to find rd_count > 1
1027 for (int i = 0; i < rd_count; i++)
1029 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE == rd[i].record_type)
1031 attr_le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
1032 attr_le->attribute =
1033 GNUNET_RECLAIM_attribute_deserialize (rd[i].data, rd[i].data_size);
1034 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
1035 cth->attrs->list_tail,
1038 else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION == rd[i].record_type)
1040 struct GNUNET_RECLAIM_AttestationListEntry *ale;
1041 ale = GNUNET_new (struct GNUNET_RECLAIM_AttestationListEntry);
1043 GNUNET_RECLAIM_attestation_deserialize (rd[i].data,
1045 GNUNET_CONTAINER_DLL_insert (cth->attests->list_head,
1046 cth->attests->list_tail,
1051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1052 "Parallel Lookup of Reference without Attestation");
1058 if (NULL != cth->parallel_lookups_head)
1059 return; // Wait for more
1060 /* Else we are done */
1061 cth->cb (cth->cb_cls, &cth->ticket.identity,
1062 cth->attrs, cth->attests, GNUNET_OK, NULL);
1068 * Cancel the lookups for attribute records
1070 * @param cls handle to the operation
1073 abort_parallel_lookups (void *cls)
1075 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1076 struct ParallelLookup *lu;
1077 struct ParallelLookup *tmp;
1079 cth->kill_task = NULL;
1080 for (lu = cth->parallel_lookups_head; NULL != lu;)
1082 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1083 GNUNET_free (lu->label);
1085 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1086 cth->parallel_lookups_tail,
1091 cth->cb (cth->cb_cls, NULL, NULL, NULL, GNUNET_SYSERR, "Aborted");
1096 * GNS result with attribute references.
1097 * For each result, we start a (parallel) lookup of the actual
1098 * attribute record under the referenced label.
1100 * @param cls handle to the operation
1101 * @param rd_cound size of the record set
1102 * @param rd record set
1105 lookup_authz_cb (void *cls,
1107 const struct GNUNET_GNSRECORD_Data *rd)
1109 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1110 struct ParallelLookup *parallel_lookup;
1113 cth->lookup_request = NULL;
1115 GNUNET_STATISTICS_update (stats,
1116 "reclaim_authz_lookup_time_total",
1117 GNUNET_TIME_absolute_get_duration (
1118 cth->lookup_start_time)
1121 GNUNET_STATISTICS_update (stats,
1122 "reclaim_authz_lookups_count",
1126 for (int i = 0; i < rd_count; i++)
1128 if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type) &&
1129 (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION_REF != rd[i].record_type))
1131 lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ticket reference found %s\n", lbl);
1133 parallel_lookup = GNUNET_new (struct ParallelLookup);
1134 parallel_lookup->handle = cth;
1135 parallel_lookup->label = lbl;
1136 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
1137 parallel_lookup->lookup_request =
1138 GNUNET_GNS_lookup (gns,
1140 &cth->ticket.identity,
1141 GNUNET_GNSRECORD_TYPE_ANY,
1142 GNUNET_GNS_LO_DEFAULT,
1143 &process_parallel_lookup_result,
1145 GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
1146 cth->parallel_lookups_tail,
1150 * We started lookups. Add a timeout task.
1151 * FIXME: Really needed here?
1153 if (NULL != cth->parallel_lookups_head)
1155 cth->kill_task = GNUNET_SCHEDULER_add_delayed (
1156 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
1157 &abort_parallel_lookups,
1162 * No references found, return empty attribute list
1164 cth->cb (cth->cb_cls, &cth->ticket.identity,
1165 cth->attrs, cth->attests, GNUNET_OK, NULL);
1172 * We first looking attribute references under the label
1173 * ticket.rnd in GNS.
1175 * @param id the audience of the ticket
1176 * @param ticket the ticket to consume
1177 * @param cb callback to call with attributes of ticket
1178 * @param cb_cls callback closure
1179 * @return handle to the operation
1181 struct RECLAIM_TICKETS_ConsumeHandle *
1182 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
1183 const struct GNUNET_RECLAIM_Ticket *ticket,
1184 RECLAIM_TICKETS_ConsumeCallback cb,
1187 struct RECLAIM_TICKETS_ConsumeHandle *cth;
1190 cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
1192 cth->identity = *id;
1193 GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
1194 cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1195 cth->attests = GNUNET_new (struct GNUNET_RECLAIM_AttestationList);
1196 cth->ticket = *ticket;
1198 cth->cb_cls = cb_cls;
1200 GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd,
1201 sizeof(cth->ticket.rnd));
1202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1203 "Looking for AuthZ info under %s\n",
1205 cth->lookup_start_time = GNUNET_TIME_absolute_get ();
1206 cth->lookup_request =
1207 GNUNET_GNS_lookup (gns,
1209 &cth->ticket.identity,
1210 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF,
1211 GNUNET_GNS_LO_DEFAULT,
1214 GNUNET_free (label);
1220 * Cancel a consume operation
1222 * @param cth the operation to cancel
1225 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
1232 /*******************************
1234 *******************************/
1237 * Cleanup ticket consume handle
1238 * @param handle the handle to clean up
1241 cleanup_issue_handle (struct TicketIssueHandle *handle)
1243 if (NULL != handle->ns_qe)
1244 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1245 GNUNET_free (handle);
1250 * Store finished, abort on error.
1251 * Else, return new ticket to caller.
1253 * @param cls handle to the operation
1254 * @param success store operation result
1255 * @param emsg error message (or NULL on success)
1258 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
1260 struct TicketIssueHandle *handle = cls;
1262 handle->ns_qe = NULL;
1263 if (GNUNET_SYSERR == success)
1265 handle->cb (handle->cb_cls,
1268 "Error storing AuthZ ticket in GNS");
1271 handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
1272 cleanup_issue_handle (handle);
1277 * Issue a new ticket.
1278 * We store references to attribute record labels and the ticket itself
1279 * under the label base64(ticket.rnd).
1281 * @param ih handle to the operation containing relevant metadata
1284 issue_ticket (struct TicketIssueHandle *ih)
1286 struct GNUNET_RECLAIM_AttributeListEntry *le;
1287 struct GNUNET_GNSRECORD_Data *attrs_record;
1290 int attrs_count = 0;
1292 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1295 //Worst case we have one attestation per attribute
1297 GNUNET_malloc (2 * attrs_count * sizeof(struct GNUNET_GNSRECORD_Data));
1299 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1301 attrs_record[i].data = &le->attribute->id;
1302 attrs_record[i].data_size = sizeof(le->attribute->id);
1303 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1304 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF;
1305 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1307 if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->attestation))
1310 for (j = 0; j < i; j++)
1312 if (attrs_record[j].record_type
1313 != GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION_REF)
1315 if (0 == memcmp (attrs_record[j].data,
1316 &le->attribute->attestation,
1317 sizeof (le->attribute->attestation)))
1321 continue; // Skip as we have already added this attestation.
1322 attrs_record[i].data = &le->attribute->attestation;
1323 attrs_record[i].data_size = sizeof(le->attribute->attestation);
1324 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1325 attrs_record[i].record_type =
1326 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION_REF;
1327 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1331 attrs_record[i].data = &ih->ticket;
1332 attrs_record[i].data_size = sizeof(struct GNUNET_RECLAIM_Ticket);
1333 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1334 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1335 attrs_record[i].flags =
1336 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1340 GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd,
1341 sizeof(ih->ticket.rnd));
1343 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1348 &store_ticket_issue_cont,
1350 GNUNET_free (attrs_record);
1351 GNUNET_free (label);
1355 /*************************************************
1356 * Ticket iteration (finding a specific ticket)
1357 *************************************************/
1361 * Namestore error on issue. Abort.
1363 * @param cls handle to the operation
1366 filter_tickets_error_cb (void *cls)
1368 struct TicketIssueHandle *tih = cls;
1371 tih->cb (tih->cb_cls,
1374 "Error storing AuthZ ticket in GNS");
1375 cleanup_issue_handle (tih);
1380 * Iterator over records.
1381 * Check if any previously issued ticket already
1382 * matches what we need to prevent duplicates and
1383 * improve resolution synergy.
1385 * @param cls handle to the operation
1386 * @param zone issuer identity
1387 * @param label ticket rnd
1388 * @param rd_count size of record set
1389 * @param rd record set
1392 filter_tickets_cb (void *cls,
1393 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1395 unsigned int rd_count,
1396 const struct GNUNET_GNSRECORD_Data *rd)
1398 struct TicketIssueHandle *tih = cls;
1399 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1401 // figure out the number of requested attributes
1402 struct GNUNET_RECLAIM_AttributeListEntry *le;
1403 unsigned int attr_cnt = 0;
1404 unsigned int attest_cnt = 0;
1406 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1409 if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->attestation))
1414 unsigned int found_attrs_cnt = 0;
1415 unsigned int found_attests_cnt = 0;
1417 for (int i = 0; i < rd_count; i++)
1420 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
1422 ticket = (struct GNUNET_RECLAIM_Ticket *) rd[i].data;
1424 if (0 == memcmp (&tih->ticket.audience,
1426 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1428 tih->ticket = *ticket;
1434 // cmp requested attributes with ticket attributes
1435 if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type) &&
1436 (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION_REF != rd[i].record_type))
1438 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1440 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1441 &le->attribute->id))
1444 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1446 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1447 &le->attribute->attestation))
1448 found_attests_cnt++;
1453 * If we found a matching ticket, return that to the caller and
1456 if ((attr_cnt == found_attrs_cnt) &&
1457 (attest_cnt == found_attests_cnt) &&
1460 GNUNET_NAMESTORE_zone_iteration_stop (tih->ns_it);
1461 tih->cb (tih->cb_cls, &tih->ticket, GNUNET_OK, NULL);
1462 cleanup_issue_handle (tih);
1466 // ticket not found in current record, checking next record set
1467 GNUNET_NAMESTORE_zone_iterator_next (tih->ns_it, 1);
1472 * Done iterating over tickets and we apparently did
1473 * not find an existing, matching ticket.
1474 * Continue by issuing a new ticket.
1476 * @param cls handle to the operation
1479 filter_tickets_finished_cb (void *cls)
1481 struct TicketIssueHandle *tih = cls;
1483 GNUNET_CRYPTO_ecdsa_key_get_public (&tih->identity, &tih->ticket.identity);
1484 GNUNET_RECLAIM_id_generate (&tih->ticket.rnd);
1490 * Issue a new reclaim ticket, thereby authorizing
1491 * the audience to access the set of provided attributes.
1493 * @param identity the issuer
1494 * @param attrs the attributes to share
1495 * @param audience the audience to share the attributes with
1496 * @param cb the callback to call with the ticket result
1497 * @param cb_cls the callback closure
1498 * FIXME: Return handle??
1501 RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1502 const struct GNUNET_RECLAIM_AttributeList *attrs,
1503 const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
1504 RECLAIM_TICKETS_TicketResult cb,
1507 struct TicketIssueHandle *tih;
1509 tih = GNUNET_new (struct TicketIssueHandle);
1511 tih->cb_cls = cb_cls;
1512 tih->attrs = GNUNET_RECLAIM_attribute_list_dup (attrs);
1513 tih->identity = *identity;
1514 tih->ticket.audience = *audience;
1516 // First check whether the ticket has already been issued
1518 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1520 &filter_tickets_error_cb,
1524 &filter_tickets_finished_cb,
1529 /************************************
1531 ************************************/
1534 * Cleanup ticket iterator
1536 * @param iter handle to the iteration
1539 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
1541 if (NULL != iter->ns_it)
1542 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1548 * Return each record of type @GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET
1549 * to the caller and proceed with the iteration.
1550 * FIXME: Should we _not_ proceed automatically here?
1552 * @param cls handle to the iteration
1553 * @param zone the ticket issuer
1554 * @param label the ticket rnd
1555 * @param rd_count number of records in record set
1556 * @param rd record set containing a ticket
1559 collect_tickets_cb (void *cls,
1560 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1562 unsigned int rd_count,
1563 const struct GNUNET_GNSRECORD_Data *rd)
1565 struct RECLAIM_TICKETS_Iterator *iter = cls;
1567 for (int i = 0; i < rd_count; i++)
1569 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1571 iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *) rd[i].data);
1574 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1579 * Signal ticket iteration has finished
1581 * @param cls handle to the iteration
1584 collect_tickets_finished_cb (void *cls)
1586 struct RECLAIM_TICKETS_Iterator *iter = cls;
1589 iter->cb (iter->cb_cls, NULL);
1590 cleanup_iter (iter);
1595 * Cancel ticket iteration on namestore error
1597 * @param cls the iteration handle
1600 collect_tickets_error_cb (void *cls)
1602 struct RECLAIM_TICKETS_Iterator *iter = cls;
1605 iter->cb (iter->cb_cls, NULL);
1606 cleanup_iter (iter);
1611 * Continue ticket iteration
1613 * @param iter the iteration to continue
1616 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
1618 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1623 * Stop a running ticket iteration
1625 * @param iter iteration to cancel
1628 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
1630 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1631 cleanup_iter (iter);
1636 * Iterate over all tickets issued by an identity
1638 * @param identity the issuing identity
1639 * @param cb ticket callback function
1640 * @param cb_cls callback closure
1641 * @return a handle to the iteration
1643 struct RECLAIM_TICKETS_Iterator *
1644 RECLAIM_TICKETS_iteration_start (
1645 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1646 RECLAIM_TICKETS_TicketIter cb,
1649 struct RECLAIM_TICKETS_Iterator *iter;
1651 iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1653 iter->cb_cls = cb_cls;
1655 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1657 &collect_tickets_error_cb,
1659 &collect_tickets_cb,
1661 &collect_tickets_finished_cb,
1668 * Initialize tickets component
1670 * @param c the configuration
1671 * @return GNUNET_SYSERR on error
1674 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1676 // Get ticket expiration time (relative) from config
1678 GNUNET_CONFIGURATION_get_value_time (c,
1680 "TICKET_REFRESH_INTERVAL",
1681 &ticket_refresh_interval))
1683 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1684 "Configured refresh interval for tickets: %s\n",
1685 GNUNET_STRINGS_relative_time_to_string (ticket_refresh_interval,
1690 ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1692 // Connect to identity and namestore services
1693 nsh = GNUNET_NAMESTORE_connect (c);
1696 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1697 "error connecting to namestore");
1698 return GNUNET_SYSERR;
1700 gns = GNUNET_GNS_connect (c);
1703 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1704 return GNUNET_SYSERR;
1706 stats = GNUNET_STATISTICS_create ("reclaim", c);
1712 * Close handles and clean up.
1713 * FIXME: cancel all pending operations (gns, ns etc)
1716 RECLAIM_TICKETS_deinit (void)
1719 GNUNET_NAMESTORE_disconnect (nsh);
1722 GNUNET_GNS_disconnect (gns);
1726 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);