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_ATTRIBUTE_ClaimList *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_ATTRIBUTE_ClaimList *attrs;
119 struct GNUNET_TIME_Absolute lookup_start_time;
124 RECLAIM_TICKETS_ConsumeCallback cb;
134 * Handle for a parallel GNS lookup job
136 struct ParallelLookup
139 struct ParallelLookup *next;
142 struct ParallelLookup *prev;
144 /* The GNS request */
145 struct GNUNET_GNS_LookupRequest *lookup_request;
147 /* The handle the return to */
148 struct RECLAIM_TICKETS_ConsumeHandle *handle;
153 struct GNUNET_TIME_Absolute lookup_start_time;
155 /* The label to look up */
161 * Ticket issue request handle
163 struct TicketIssueHandle
166 * Attributes to issue
168 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
173 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
178 struct GNUNET_RECLAIM_Ticket ticket;
183 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
188 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
193 RECLAIM_TICKETS_TicketResult cb;
205 struct RECLAIM_TICKETS_Iterator
208 * Namestore queue entry
210 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
215 RECLAIM_TICKETS_TicketIter cb;
224 struct RevokedAttributeEntry
229 struct RevokedAttributeEntry *next;
234 struct RevokedAttributeEntry *prev;
237 * Old ID of the attribute
242 * New ID of the attribute
249 * Ticket revocation request handle
251 struct RECLAIM_TICKETS_RevokeHandle
256 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
261 RECLAIM_TICKETS_RevokeCallback cb;
271 struct GNUNET_RECLAIM_Ticket ticket;
276 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
281 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
286 struct RevokedAttributeEntry *attrs_head;
291 struct RevokedAttributeEntry *attrs_tail;
294 * Current attribute to move
296 struct RevokedAttributeEntry *move_attr;
299 * Number of attributes in ticket
301 unsigned int ticket_attrs;
306 struct TicketRecordsEntry *tickets_to_update_head;
311 struct TicketRecordsEntry *tickets_to_update_tail;
316 * Ticket expiration interval
318 static struct GNUNET_TIME_Relative ticket_refresh_interval;
321 /* Namestore handle */
322 static struct GNUNET_NAMESTORE_Handle *nsh;
326 static struct GNUNET_GNS_Handle *gns;
329 /* Handle to the statistics service */
330 static struct GNUNET_STATISTICS_Handle *stats;
334 * Cleanup revoke handle
336 * @param rh the ticket revocation handle
339 cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
341 struct RevokedAttributeEntry *ae;
342 struct TicketRecordsEntry *le;
344 if (NULL != rh->ns_qe)
345 GNUNET_NAMESTORE_cancel (rh->ns_qe);
346 if (NULL != rh->ns_it)
347 GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
348 while (NULL != (ae = rh->attrs_head))
350 GNUNET_CONTAINER_DLL_remove (rh->attrs_head, rh->attrs_tail, ae);
353 while (NULL != (le = rh->tickets_to_update_head))
355 GNUNET_CONTAINER_DLL_remove (rh->tickets_to_update_head,
356 rh->tickets_to_update_head,
358 if (NULL != le->data)
359 GNUNET_free (le->data);
360 if (NULL != le->label)
361 GNUNET_free (le->label);
369 * For each ticket, store new, updated attribute references
370 * (Implementation further below)
372 * @param cls handle to the operation
375 process_tickets (void *cls);
379 * Finished storing updated attribute references.
380 * Abort on error, else continue processing tickets
382 * @param cls handle to the operation
383 * @param success result of namestore operation
384 * @param emsg (NULL on success)
387 ticket_processed (void *cls, int32_t success, const char *emsg)
389 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
392 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
397 * For each ticket, store new, updated attribute references
399 * @param cls handle to the operation
402 process_tickets (void *cls)
404 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
405 struct TicketRecordsEntry *le;
406 struct RevokedAttributeEntry *ae;
408 if (NULL == rvk->tickets_to_update_head)
410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
411 "Finished updatding tickets, success\n");
412 rvk->cb (rvk->cb_cls, GNUNET_OK);
416 le = rvk->tickets_to_update_head;
417 GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
418 rvk->tickets_to_update_tail,
420 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
421 if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
426 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
427 "Unable to deserialize ticket record(s)\n");
428 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
432 for (int i = 0; i < le->rd_count; i++)
434 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
436 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
438 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(uint64_t)))
440 rd[i].data = &ae->new_id;
443 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
450 GNUNET_free (le->label);
451 GNUNET_free (le->data);
457 * Done collecting tickets. Start processing.
459 * @param cls handle to the operation
462 rvk_ticket_update_finished (void *cls)
464 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
467 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
472 * We need to update all other tickets with the new attribute IDs.
473 * We first collect them all. Processing after.
475 * @param cls handle to the operation
476 * @param zone ticket issuer private key
477 * @param label ticket rnd
478 * @param rd_cound size of record set
479 * @param rd record set
482 rvk_ticket_update (void *cls,
483 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
485 unsigned int rd_count,
486 const struct GNUNET_GNSRECORD_Data *rd)
488 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
489 struct TicketRecordsEntry *le;
490 struct RevokedAttributeEntry *ae;
491 int has_changed = GNUNET_NO;
493 /** Let everything point to the old record **/
494 for (int i = 0; i < rd_count; i++)
496 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
498 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
500 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(uint64_t)))
502 has_changed = GNUNET_YES;
505 if (GNUNET_YES == has_changed)
508 if (GNUNET_YES == has_changed)
510 le = GNUNET_new (struct TicketRecordsEntry);
511 le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
512 le->data = GNUNET_malloc (le->data_size);
513 le->rd_count = rd_count;
514 le->label = GNUNET_strdup (label);
515 GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
516 GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
517 rvk->tickets_to_update_tail,
520 GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
525 * Error iterating namestore. Abort.
527 * @param cls handle to the operation
530 rvk_ns_iter_err (void *cls)
532 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
535 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
536 "Namestore error on revocation (id=%" PRIu64 "\n",
537 rvk->move_attr->old_id);
538 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
544 * Error storing new attribute in namestore. Abort
546 * @param cls handle to the operation
549 rvk_ns_err (void *cls)
551 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
554 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
555 "Namestore error on revocation (id=%" PRIu64 "\n",
556 rvk->move_attr->old_id);
557 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
563 * We change every attribute ID of the ticket attributes we
565 * When we are done, we need to update any other ticket which
566 * included references to any of the changed attributes.
567 * (Implementation further below)
569 * @param rvk handle to the operation
572 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
576 * Delayed continuation for move_attrs
578 * @param cls handle to the operation.
581 move_attrs_cont (void *cls)
583 move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
588 * Done deleting the old record. Abort on error.
589 * Else, continue updating attribute IDs.
591 * @param cls handle to the operation
592 * @param success result of the namestore operation
593 * @param emsg error message (NULL on success)
596 del_attr_finished (void *cls, int32_t success, const char *emsg)
598 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
601 if (GNUNET_SYSERR == success)
603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
604 "Error removing attribute: %s\n",
606 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
610 rvk->move_attr = rvk->move_attr->next;
611 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
616 * Updated an attribute ID.
617 * Abort on error if namestore operation failed.
618 * Else, we have to delete the old record.
620 * @param cls handle to the operation
621 * @param success result of the store operation
622 * @param emsg error message (NULL on success)
625 move_attr_finished (void *cls, int32_t success, const char *emsg)
627 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
631 if (GNUNET_SYSERR == success)
633 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
634 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
638 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
640 GNUNET_assert (NULL != label);
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
642 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
654 * Got the referenced attribute. Updating the ID
656 * @param cls handle to the operation
657 * @param zone issuer identity
658 * @param label attribute ID
659 * @param rd_count size of record set (should be 1)
660 * @param rd record set (the attribute)
663 rvk_move_attr_cb (void *cls,
664 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
666 unsigned int rd_count,
667 const struct GNUNET_GNSRECORD_Data *rd)
669 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
670 struct GNUNET_GNSRECORD_Data new_rd[rd_count];
671 struct RevokedAttributeEntry *le;
678 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
679 "The claim %s no longer exists!\n",
682 rvk->move_attr = le->next;
683 GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
685 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
688 rvk->move_attr->new_id =GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
692 for (int i = 0; i < rd_count; i++)
694 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR == rd[i].record_type)
696 /** find a new place for this attribute **/
697 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
698 claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd[i].data, rd[i].data_size);
699 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
700 "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
703 claim->id = rvk->move_attr->new_id;
704 new_rd[i].data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
705 attr_data = GNUNET_malloc (rd[i].data_size);
706 new_rd[i].data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
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;
711 new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
715 } else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR == rd[i].record_type)
717 struct GNUNET_RECLAIM_ATTESTATION_Claim *attest;
718 attest=GNUNET_RECLAIM_ATTESTATION_deserialize(rd[i].data, rd[i].data_size);
719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720 "Attestation to update: Name=%s, ID=%" PRIu64 "\n",
723 attest->id = rvk->move_attr->new_id;
724 new_rd[i].data_size = GNUNET_RECLAIM_ATTESTATION_serialize_get_size (attest);
725 attr_data = GNUNET_malloc (rd[i].data_size);
726 new_rd[i].data_size = GNUNET_RECLAIM_ATTESTATION_serialize (attest, attr_data);
727 new_rd[i].data = attr_data;
728 new_rd[i].record_type = rd[i].record_type;
729 new_rd[i].flags = rd[i].flags;
730 new_rd[i].expiration_time = rd[i].expiration_time;
731 new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id, sizeof(uint64_t));
732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attestation %s\n", new_label);
733 GNUNET_free (attest);
734 } else if (GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE == rd[i].record_type)
736 struct GNUNET_RECLAIM_ATTESTATION_REFERENCE *reference;
737 reference=GNUNET_RECLAIM_ATTESTATION_REF_deserialize(rd[i].data, rd[i].data_size);
738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
739 "Reference to update: Name=%s, ID=%" PRIu64 "\n",
742 reference->id = rvk->move_attr->new_id;
743 reference->id_attest = rvk->move_attr->new_id;
744 new_rd[i].data_size = GNUNET_RECLAIM_ATTESTATION_REF_serialize_get_size (reference);
745 attr_data = GNUNET_malloc (rd[i].data_size);
746 new_rd[i].data_size = GNUNET_RECLAIM_ATTESTATION_REF_serialize (reference, attr_data);
747 new_rd[i].data = attr_data;
748 new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id, sizeof(uint64_t));
749 new_rd[i].record_type = rd[i].record_type;
750 new_rd[i].flags = rd[i].flags;
751 new_rd[i].expiration_time = rd[i].expiration_time;
752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding reference %s\n", new_label);
753 GNUNET_free (reference);
756 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
763 GNUNET_free (new_label);
764 GNUNET_free (attr_data);
769 * We change every attribute ID of the ticket attributes we
771 * When we are done, we need to update any other ticket which
772 * included references to any of the changed attributes.
774 * @param rvk handle to the operation
777 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
781 if (NULL == rvk->move_attr)
783 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
785 GNUNET_NAMESTORE_zone_iteration_start (nsh,
791 &rvk_ticket_update_finished,
795 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving claim %s\n", label);
799 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
811 * Finished deleting ticket and attribute references.
813 * Else, we start changing every attribute ID in the
814 * found attribute references so that access is no longer
817 * @param cls handle to the operation
818 * @param success Namestore operation return value
819 * @param emsg error message (NULL on success)
822 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
824 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
827 if (GNUNET_SYSERR == success)
829 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
830 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
835 if (0 == rvk->ticket_attrs)
837 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
838 "No attributes to move... strange\n");
839 rvk->cb (rvk->cb_cls, GNUNET_OK);
843 rvk->move_attr = rvk->attrs_head;
849 * We found the attribute references.
850 * Store them for later and remove the record set.
852 * @param cls handle to the operation
853 * @param zone the issuer key
854 * @param label ticket rnd
855 * @param rd_cound size of record set
856 * @param rd record set
859 revoke_attrs_cb (void *cls,
860 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
862 unsigned int rd_count,
863 const struct GNUNET_GNSRECORD_Data *rd)
866 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
867 struct RevokedAttributeEntry *le;
871 * Temporarily store attribute references.
874 for (int i = 0; i < rd_count; i++)
876 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
878 le = GNUNET_new (struct RevokedAttributeEntry);
879 le->old_id = *((uint64_t *) rd[i].data);
880 GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
884 /** Remove attribute references **/
885 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
896 * Failed to query namestore. Abort operation
898 * @param cls handle to the operation
901 rvk_attrs_err_cb (void *cls)
903 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
905 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
912 * We start by looking up attribute references in order
913 * to change attribute IDs.
915 * @param ticket ticket to revoke
916 * @param identity private key of issuer
917 * @param cb revocation status callback
918 * @param cb_cls callback closure
919 * @return handle to the operation
921 struct RECLAIM_TICKETS_RevokeHandle *
922 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
923 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
924 RECLAIM_TICKETS_RevokeCallback cb,
927 struct RECLAIM_TICKETS_RevokeHandle *rvk;
930 rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
932 rvk->cb_cls = cb_cls;
933 rvk->identity = *identity;
934 rvk->ticket = *ticket;
935 GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
936 /** Get shared attributes **/
937 label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
938 GNUNET_assert (NULL != label);
939 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
952 * Cancel a revocation.
954 * @param rh handle to the operation
957 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
959 GNUNET_assert (NULL != rh);
964 /*******************************
966 *******************************/
969 * Cleanup ticket consume handle
971 * @param cth the handle to clean up
974 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
976 struct ParallelLookup *lu;
978 if (NULL != cth->lookup_request)
979 GNUNET_GNS_lookup_cancel (cth->lookup_request);
980 if (NULL != cth->kill_task)
981 GNUNET_SCHEDULER_cancel (cth->kill_task);
982 while (NULL != (lu = cth->parallel_lookups_head))
984 if (NULL != lu->lookup_request)
985 GNUNET_GNS_lookup_cancel (lu->lookup_request);
986 GNUNET_free_non_null (lu->label);
987 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
988 cth->parallel_lookups_tail,
993 if (NULL != cth->attrs)
994 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cth->attrs);
1000 * We found an attribute record.
1002 * @param cls handle to the operation
1003 * @param rd_cound size of record set
1004 * @param rd record set
1007 process_parallel_lookup_result (void *cls,
1009 const struct GNUNET_GNSRECORD_Data *rd)
1011 struct ParallelLookup *parallel_lookup = cls;
1012 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
1013 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
1015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 "Parallel lookup finished (count=%u)\n",
1019 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1020 cth->parallel_lookups_tail,
1022 GNUNET_free (parallel_lookup->label);
1024 GNUNET_STATISTICS_update (stats,
1025 "attribute_lookup_time_total",
1026 GNUNET_TIME_absolute_get_duration (
1027 parallel_lookup->lookup_start_time)
1030 GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
1033 GNUNET_free (parallel_lookup);
1036 // REMARK: It is possible now to find rd_count > 1
1037 for (int i = 0; i < rd_count; i++)
1039 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR == rd[i].record_type)
1041 attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
1043 GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd[i].data, rd[i].data_size);
1044 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
1045 cth->attrs->list_tail,
1047 attr_le->reference = NULL;
1048 attr_le->attest = NULL;
1050 else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR == rd[i].record_type)
1052 /**Ignore all plain attestations
1053 *attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
1055 * GNUNET_RECLAIM_ATTESTATION_deserialize (rd[i].data, rd[i].data_size);
1056 *GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
1057 * cth->attrs->list_tail,
1062 else if (GNUNET_GNSRECORD_TYPE_RECLAIM_REFERENCE == rd[i].record_type)
1064 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le2;
1065 attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
1066 attr_le2 = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
1067 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTEST_ATTR == rd[0].record_type)
1069 attr_le->attest = GNUNET_RECLAIM_ATTESTATION_deserialize (rd[0].data,
1072 attr_le2->reference =
1073 GNUNET_RECLAIM_ATTESTATION_REF_deserialize (rd[i].data,
1075 attr_le->claim = NULL;
1076 attr_le->reference = NULL;
1077 attr_le2->claim = NULL;
1078 attr_le2->attest = NULL;
1079 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
1080 cth->attrs->list_tail,
1082 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
1083 cth->attrs->list_tail,
1088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089 "Parallel Lookup of Reference without Attestation");
1096 if (NULL != cth->parallel_lookups_head)
1097 return; // Wait for more
1098 /* Else we are done */
1099 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1105 * Cancel the lookups for attribute records
1107 * @param cls handle to the operation
1110 abort_parallel_lookups (void *cls)
1112 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1113 struct ParallelLookup *lu;
1114 struct ParallelLookup *tmp;
1116 cth->kill_task = NULL;
1117 for (lu = cth->parallel_lookups_head; NULL != lu;)
1119 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1120 GNUNET_free (lu->label);
1122 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1123 cth->parallel_lookups_tail,
1128 cth->cb (cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
1133 * GNS result with attribute references.
1134 * For each result, we start a (parallel) lookup of the actual
1135 * attribute record under the referenced label.
1137 * @param cls handle to the operation
1138 * @param rd_cound size of the record set
1139 * @param rd record set
1142 lookup_authz_cb (void *cls,
1144 const struct GNUNET_GNSRECORD_Data *rd)
1146 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1147 struct ParallelLookup *parallel_lookup;
1150 cth->lookup_request = NULL;
1152 GNUNET_STATISTICS_update (stats,
1153 "reclaim_authz_lookup_time_total",
1154 GNUNET_TIME_absolute_get_duration (
1155 cth->lookup_start_time)
1158 GNUNET_STATISTICS_update (stats,
1159 "reclaim_authz_lookups_count",
1163 for (int i = 0; i < rd_count; i++)
1165 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1167 lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
1168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
1169 parallel_lookup = GNUNET_new (struct ParallelLookup);
1170 parallel_lookup->handle = cth;
1171 parallel_lookup->label = lbl;
1172 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
1173 parallel_lookup->lookup_request =
1174 GNUNET_GNS_lookup (gns,
1176 &cth->ticket.identity,
1177 GNUNET_GNSRECORD_TYPE_ANY,
1178 GNUNET_GNS_LO_DEFAULT,
1179 &process_parallel_lookup_result,
1181 GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
1182 cth->parallel_lookups_tail,
1186 * We started lookups. Add a timeout task.
1187 * FIXME: Really needed here?
1189 if (NULL != cth->parallel_lookups_head)
1191 cth->kill_task = GNUNET_SCHEDULER_add_delayed (
1192 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
1193 &abort_parallel_lookups,
1198 * No references found, return empty attribute list
1200 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1207 * We first looking attribute references under the label
1208 * ticket.rnd in GNS.
1210 * @param id the audience of the ticket
1211 * @param ticket the ticket to consume
1212 * @param cb callback to call with attributes of ticket
1213 * @param cb_cls callback closure
1214 * @return handle to the operation
1216 struct RECLAIM_TICKETS_ConsumeHandle *
1217 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
1218 const struct GNUNET_RECLAIM_Ticket *ticket,
1219 RECLAIM_TICKETS_ConsumeCallback cb,
1222 struct RECLAIM_TICKETS_ConsumeHandle *cth;
1225 cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
1227 cth->identity = *id;
1228 GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
1229 cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1230 cth->ticket = *ticket;
1232 cth->cb_cls = cb_cls;
1234 GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof(uint64_t));
1235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1236 "Looking for AuthZ info under %s\n",
1238 cth->lookup_start_time = GNUNET_TIME_absolute_get ();
1239 cth->lookup_request =
1240 GNUNET_GNS_lookup (gns,
1242 &cth->ticket.identity,
1243 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
1244 GNUNET_GNS_LO_DEFAULT,
1247 GNUNET_free (label);
1253 * Cancel a consume operation
1255 * @param cth the operation to cancel
1258 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
1265 /*******************************
1267 *******************************/
1270 * Cleanup ticket consume handle
1271 * @param handle the handle to clean up
1274 cleanup_issue_handle (struct TicketIssueHandle *handle)
1276 if (NULL != handle->ns_qe)
1277 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1278 GNUNET_free (handle);
1283 * Store finished, abort on error.
1284 * Else, return new ticket to caller.
1286 * @param cls handle to the operation
1287 * @param success store operation result
1288 * @param emsg error message (or NULL on success)
1291 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
1293 struct TicketIssueHandle *handle = cls;
1295 handle->ns_qe = NULL;
1296 if (GNUNET_SYSERR == success)
1298 handle->cb (handle->cb_cls,
1301 "Error storing AuthZ ticket in GNS");
1304 handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
1305 cleanup_issue_handle (handle);
1310 * Issue a new ticket.
1311 * We store references to attribute record labels and the ticket itself
1312 * under the label base64(ticket.rnd).
1314 * @param ih handle to the operation containing relevant metadata
1317 issue_ticket (struct TicketIssueHandle *ih)
1319 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1320 struct GNUNET_GNSRECORD_Data *attrs_record;
1322 size_t list_len = 1;
1324 char *attest_string;
1326 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1330 GNUNET_malloc (list_len * sizeof(struct GNUNET_GNSRECORD_Data));
1332 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1334 if (NULL != le->claim)
1336 attrs_record[i].data = &le->claim->id;
1337 attrs_record[i].data_size = sizeof(le->claim->id);
1339 else if (NULL != le->attest)
1341 // REMARK: Since we only store IDs, the references are irrelevant
1343 GNUNET_asprintf (&attest_string,"%d",le->attest->id);
1346 if (0 == strcmp (attest_string,GNUNET_STRINGS_data_to_string_alloc (
1347 attrs_record[j].data, attrs_record[j].data_size)))
1356 attrs_record[i].data = &le->attest->id;
1357 attrs_record[i].data_size = sizeof(le->attest->id);
1359 else if (NULL != le->reference)
1365 GNUNET_asprintf (&attest_string,"%d",le->attest->id);
1368 if (strcmp(attest_string, GNUNET_STRINGS_data_to_string_alloc (
1369 attrs_record[j].data, attrs_record[j].data_size)))
1375 attrs_record[i].data = &le->reference->id;
1376 attrs_record[i].data_size = sizeof(le->reference->id);
1380 * FIXME: Should this be the attribute expiration time or ticket
1381 * refresh interval? Probably min(attrs.expiration)
1383 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1384 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
1385 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1388 attrs_record[i].data = &ih->ticket;
1389 attrs_record[i].data_size = sizeof(struct GNUNET_RECLAIM_Ticket);
1390 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1391 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1392 attrs_record[i].flags =
1393 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1396 GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof(uint64_t));
1398 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1403 &store_ticket_issue_cont,
1405 GNUNET_free (attrs_record);
1406 GNUNET_free (label);
1410 /*************************************************
1411 * Ticket iteration (finding a specific ticket)
1412 *************************************************/
1416 * Namestore error on issue. Abort.
1418 * @param cls handle to the operation
1421 filter_tickets_error_cb (void *cls)
1423 struct TicketIssueHandle *tih = cls;
1426 tih->cb (tih->cb_cls,
1429 "Error storing AuthZ ticket in GNS");
1430 cleanup_issue_handle (tih);
1435 * Iterator over records.
1436 * Check if any previously issued ticket already
1437 * matches what we need to prevent duplicates and
1438 * improve resolution synergy.
1440 * @param cls handle to the operation
1441 * @param zone issuer identity
1442 * @param label ticket rnd
1443 * @param rd_count size of record set
1444 * @param rd record set
1447 filter_tickets_cb (void *cls,
1448 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1450 unsigned int rd_count,
1451 const struct GNUNET_GNSRECORD_Data *rd)
1453 struct TicketIssueHandle *tih = cls;
1454 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1456 // figure out the number of requested attributes
1457 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1458 unsigned int attr_cnt = 0;
1460 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1464 unsigned int found_attrs_cnt = 0;
1466 for (int i = 0; i < rd_count; i++)
1469 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
1471 ticket = (struct GNUNET_RECLAIM_Ticket *) rd[i].data;
1473 if (0 == memcmp (&tih->ticket.audience,
1475 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1477 tih->ticket = *ticket;
1483 // cmp requested attributes with ticket attributes
1484 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1486 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1488 // cmp attr_ref id with requested attr id
1489 if (NULL !=le->claim)
1491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1492 " %" PRIu64 "\n %" PRIu64 "\n",
1493 *((uint64_t *) rd[i].data),
1495 if (0 == memcmp (rd[i].data, &le->claim->id, sizeof(uint64_t)))
1498 else if (NULL !=le->attest)
1500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1501 " %" PRIu64 "\n %" PRIu64 "\n",
1502 *((uint64_t *) rd[i].data),
1504 if (0 == memcmp (rd[i].data, &le->attest->id, sizeof(uint64_t)))
1507 else if (NULL != le->reference)
1509 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1510 " %" PRIu64 "\n %" PRIu64 "\n",
1511 *((uint64_t *) rd[i].data),
1513 if (0 == memcmp (rd[i].data, &le->reference->id, sizeof(uint64_t)))
1521 * If we found a matching ticket, return that to the caller and
1524 if ((attr_cnt == found_attrs_cnt) && (NULL != ticket))
1526 GNUNET_NAMESTORE_zone_iteration_stop (tih->ns_it);
1527 tih->cb (tih->cb_cls, &tih->ticket, GNUNET_OK, NULL);
1528 cleanup_issue_handle (tih);
1532 // ticket not found in current record, checking next record set
1533 GNUNET_NAMESTORE_zone_iterator_next (tih->ns_it, 1);
1538 * Done iterating over tickets and we apparently did
1539 * not find an existing, matching ticket.
1540 * Continue by issuing a new ticket.
1542 * @param cls handle to the operation
1545 filter_tickets_finished_cb (void *cls)
1547 struct TicketIssueHandle *tih = cls;
1549 GNUNET_CRYPTO_ecdsa_key_get_public (&tih->identity, &tih->ticket.identity);
1551 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
1557 * Issue a new reclaim ticket, thereby authorizing
1558 * the audience to access the set of provided attributes.
1560 * @param identity the issuer
1561 * @param attrs the attributes to share
1562 * @param audience the audience to share the attributes with
1563 * @param cb the callback to call with the ticket result
1564 * @param cb_cls the callback closure
1565 * FIXME: Return handle??
1568 RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1569 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1570 const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
1571 RECLAIM_TICKETS_TicketResult cb,
1574 struct TicketIssueHandle *tih;
1576 tih = GNUNET_new (struct TicketIssueHandle);
1578 tih->cb_cls = cb_cls;
1579 tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
1580 tih->identity = *identity;
1581 tih->ticket.audience = *audience;
1583 // First check whether the ticket has already been issued
1585 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1587 &filter_tickets_error_cb,
1591 &filter_tickets_finished_cb,
1596 /************************************
1598 ************************************/
1601 * Cleanup ticket iterator
1603 * @param iter handle to the iteration
1606 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
1608 if (NULL != iter->ns_it)
1609 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1615 * Return each record of type @GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET
1616 * to the caller and proceed with the iteration.
1617 * FIXME: Should we _not_ proceed automatically here?
1619 * @param cls handle to the iteration
1620 * @param zone the ticket issuer
1621 * @param label the ticket rnd
1622 * @param rd_count number of records in record set
1623 * @param rd record set containing a ticket
1626 collect_tickets_cb (void *cls,
1627 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1629 unsigned int rd_count,
1630 const struct GNUNET_GNSRECORD_Data *rd)
1632 struct RECLAIM_TICKETS_Iterator *iter = cls;
1634 for (int i = 0; i < rd_count; i++)
1636 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1638 iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *) rd[i].data);
1641 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1646 * Signal ticket iteration has finished
1648 * @param cls handle to the iteration
1651 collect_tickets_finished_cb (void *cls)
1653 struct RECLAIM_TICKETS_Iterator *iter = cls;
1656 iter->cb (iter->cb_cls, NULL);
1657 cleanup_iter (iter);
1662 * Cancel ticket iteration on namestore error
1664 * @param cls the iteration handle
1667 collect_tickets_error_cb (void *cls)
1669 struct RECLAIM_TICKETS_Iterator *iter = cls;
1672 iter->cb (iter->cb_cls, NULL);
1673 cleanup_iter (iter);
1678 * Continue ticket iteration
1680 * @param iter the iteration to continue
1683 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
1685 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1690 * Stop a running ticket iteration
1692 * @param iter iteration to cancel
1695 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
1697 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1698 cleanup_iter (iter);
1703 * Iterate over all tickets issued by an identity
1705 * @param identity the issuing identity
1706 * @param cb ticket callback function
1707 * @param cb_cls callback closure
1708 * @return a handle to the iteration
1710 struct RECLAIM_TICKETS_Iterator *
1711 RECLAIM_TICKETS_iteration_start (
1712 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1713 RECLAIM_TICKETS_TicketIter cb,
1716 struct RECLAIM_TICKETS_Iterator *iter;
1718 iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1720 iter->cb_cls = cb_cls;
1722 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1724 &collect_tickets_error_cb,
1726 &collect_tickets_cb,
1728 &collect_tickets_finished_cb,
1735 * Initialize tickets component
1737 * @param c the configuration
1738 * @return GNUNET_SYSERR on error
1741 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1743 // Get ticket expiration time (relative) from config
1745 GNUNET_CONFIGURATION_get_value_time (c,
1747 "TICKET_REFRESH_INTERVAL",
1748 &ticket_refresh_interval))
1750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1751 "Configured refresh interval for tickets: %s\n",
1752 GNUNET_STRINGS_relative_time_to_string (ticket_refresh_interval,
1757 ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1759 // Connect to identity and namestore services
1760 nsh = GNUNET_NAMESTORE_connect (c);
1763 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1764 "error connecting to namestore");
1765 return GNUNET_SYSERR;
1767 gns = GNUNET_GNS_connect (c);
1770 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1771 return GNUNET_SYSERR;
1773 stats = GNUNET_STATISTICS_create ("reclaim", c);
1779 * Close handles and clean up.
1780 * FIXME: cancel all pending operations (gns, ns etc)
1783 RECLAIM_TICKETS_deinit (void)
1786 GNUNET_NAMESTORE_disconnect (nsh);
1789 GNUNET_GNS_disconnect (gns);
1793 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);