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;
335 * Cleanup revoke handle
337 * @param rh the ticket revocation handle
340 cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
342 struct RevokedAttributeEntry *ae;
343 struct TicketRecordsEntry *le;
345 if (NULL != rh->ns_qe)
346 GNUNET_NAMESTORE_cancel (rh->ns_qe);
347 if (NULL != rh->ns_it)
348 GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
349 while (NULL != (ae = rh->attrs_head))
351 GNUNET_CONTAINER_DLL_remove (rh->attrs_head, rh->attrs_tail, ae);
354 while (NULL != (le = rh->tickets_to_update_head))
356 GNUNET_CONTAINER_DLL_remove (rh->tickets_to_update_head,
357 rh->tickets_to_update_head,
359 if (NULL != le->data)
360 GNUNET_free (le->data);
361 if (NULL != le->label)
362 GNUNET_free (le->label);
370 * For each ticket, store new, updated attribute references
371 * (Implementation further below)
373 * @param cls handle to the operation
376 process_tickets (void *cls);
380 * Finished storing updated attribute references.
381 * Abort on error, else continue processing tickets
383 * @param cls handle to the operation
384 * @param success result of namestore operation
385 * @param emsg (NULL on success)
388 ticket_processed (void *cls, int32_t success, const char *emsg)
390 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
393 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
398 * For each ticket, store new, updated attribute references
400 * @param cls handle to the operation
403 process_tickets (void *cls)
405 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
406 struct TicketRecordsEntry *le;
407 struct RevokedAttributeEntry *ae;
409 if (NULL == rvk->tickets_to_update_head)
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "Finished updatding tickets, success\n");
413 rvk->cb (rvk->cb_cls, GNUNET_OK);
417 le = rvk->tickets_to_update_head;
418 GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
419 rvk->tickets_to_update_tail,
421 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
422 if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
427 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
428 "Unable to deserialize ticket record(s)\n");
429 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
433 for (int i = 0; i < le->rd_count; i++)
435 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
437 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
439 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(uint64_t)))
441 rd[i].data = &ae->new_id;
444 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
451 GNUNET_free (le->label);
452 GNUNET_free (le->data);
458 * Done collecting tickets. Start processing.
460 * @param cls handle to the operation
463 rvk_ticket_update_finished (void *cls)
465 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
468 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
473 * We need to update all other tickets with the new attribute IDs.
474 * We first collect them all. Processing after.
476 * @param cls handle to the operation
477 * @param zone ticket issuer private key
478 * @param label ticket rnd
479 * @param rd_cound size of record set
480 * @param rd record set
483 rvk_ticket_update (void *cls,
484 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
486 unsigned int rd_count,
487 const struct GNUNET_GNSRECORD_Data *rd)
489 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
490 struct TicketRecordsEntry *le;
491 struct RevokedAttributeEntry *ae;
492 int has_changed = GNUNET_NO;
494 /** Let everything point to the old record **/
495 for (int i = 0; i < rd_count; i++)
497 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
499 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
501 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(uint64_t)))
503 has_changed = GNUNET_YES;
506 if (GNUNET_YES == has_changed)
509 if (GNUNET_YES == has_changed)
511 le = GNUNET_new (struct TicketRecordsEntry);
512 le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
513 le->data = GNUNET_malloc (le->data_size);
514 le->rd_count = rd_count;
515 le->label = GNUNET_strdup (label);
516 GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
517 GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
518 rvk->tickets_to_update_tail,
521 GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
526 * Error iterating namestore. Abort.
528 * @param cls handle to the operation
531 rvk_ns_iter_err (void *cls)
533 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
536 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
537 "Namestore error on revocation (id=%" PRIu64 "\n",
538 rvk->move_attr->old_id);
539 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
545 * Error storing new attribute in namestore. Abort
547 * @param cls handle to the operation
550 rvk_ns_err (void *cls)
552 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
555 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
556 "Namestore error on revocation (id=%" PRIu64 "\n",
557 rvk->move_attr->old_id);
558 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
564 * We change every attribute ID of the ticket attributes we
566 * When we are done, we need to update any other ticket which
567 * included references to any of the changed attributes.
568 * (Implementation further below)
570 * @param rvk handle to the operation
573 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
577 * Delayed continuation for move_attrs
579 * @param cls handle to the operation.
582 move_attrs_cont (void *cls)
584 move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
589 * Done deleting the old record. Abort on error.
590 * Else, continue updating attribute IDs.
592 * @param cls handle to the operation
593 * @param success result of the namestore operation
594 * @param emsg error message (NULL on success)
597 del_attr_finished (void *cls, int32_t success, const char *emsg)
599 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
602 if (GNUNET_SYSERR == success)
604 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
605 "Error removing attribute: %s\n",
607 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
611 rvk->move_attr = rvk->move_attr->next;
612 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
617 * Updated an attribute ID.
618 * Abort on error if namestore operation failed.
619 * Else, we have to delete the old record.
621 * @param cls handle to the operation
622 * @param success result of the store operation
623 * @param emsg error message (NULL on success)
626 move_attr_finished (void *cls, int32_t success, const char *emsg)
628 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
632 if (GNUNET_SYSERR == success)
634 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
635 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
639 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
641 GNUNET_assert (NULL != label);
642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
643 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
655 * Got the referenced attribute. Updating the ID
657 * @param cls handle to the operation
658 * @param zone issuer identity
659 * @param label attribute ID
660 * @param rd_count size of record set (should be 1)
661 * @param rd record set (the attribute)
664 rvk_move_attr_cb (void *cls,
665 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
667 unsigned int rd_count,
668 const struct GNUNET_GNSRECORD_Data *rd)
670 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
671 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
672 struct GNUNET_GNSRECORD_Data new_rd;
673 struct RevokedAttributeEntry *le;
680 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
681 "The attribute %s no longer exists!\n",
684 rvk->move_attr = le->next;
685 GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
687 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
690 /** find a new place for this attribute **/
691 rvk->move_attr->new_id =
692 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
694 claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
695 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
696 "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
699 claim->id = rvk->move_attr->new_id;
700 new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
701 attr_data = GNUNET_malloc (rd->data_size);
702 new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
703 new_rd.data = attr_data;
704 new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
707 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
714 GNUNET_free (new_label);
716 GNUNET_free (attr_data);
721 * We change every attribute ID of the ticket attributes we
723 * When we are done, we need to update any other ticket which
724 * included references to any of the changed attributes.
726 * @param rvk handle to the operation
729 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
733 if (NULL == rvk->move_attr)
735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
737 GNUNET_NAMESTORE_zone_iteration_start (nsh,
743 &rvk_ticket_update_finished,
747 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label);
751 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
763 * Finished deleting ticket and attribute references.
765 * Else, we start changing every attribute ID in the
766 * found attribute references so that access is no longer
769 * @param cls handle to the operation
770 * @param success Namestore operation return value
771 * @param emsg error message (NULL on success)
774 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
776 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
779 if (GNUNET_SYSERR == success)
781 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
782 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
787 if (0 == rvk->ticket_attrs)
789 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
790 "No attributes to move... strange\n");
791 rvk->cb (rvk->cb_cls, GNUNET_OK);
795 rvk->move_attr = rvk->attrs_head;
801 * We found the attribute references.
802 * Store them for later and remove the record set.
804 * @param cls handle to the operation
805 * @param zone the issuer key
806 * @param label ticket rnd
807 * @param rd_cound size of record set
808 * @param rd record set
811 revoke_attrs_cb (void *cls,
812 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
814 unsigned int rd_count,
815 const struct GNUNET_GNSRECORD_Data *rd)
818 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
819 struct RevokedAttributeEntry *le;
823 * Temporarily store attribute references.
826 for (int i = 0; i < rd_count; i++)
828 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
830 le = GNUNET_new (struct RevokedAttributeEntry);
831 le->old_id = *((uint64_t *) rd[i].data);
832 GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
836 /** Remove attribute references **/
837 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
848 * Failed to query namestore. Abort operation
850 * @param cls handle to the operation
853 rvk_attrs_err_cb (void *cls)
855 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
857 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
864 * We start by looking up attribute references in order
865 * to change attribute IDs.
867 * @param ticket ticket to revoke
868 * @param identity private key of issuer
869 * @param cb revocation status callback
870 * @param cb_cls callback closure
871 * @return handle to the operation
873 struct RECLAIM_TICKETS_RevokeHandle *
874 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
875 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
876 RECLAIM_TICKETS_RevokeCallback cb,
879 struct RECLAIM_TICKETS_RevokeHandle *rvk;
882 rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
884 rvk->cb_cls = cb_cls;
885 rvk->identity = *identity;
886 rvk->ticket = *ticket;
887 GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
888 /** Get shared attributes **/
889 label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
890 GNUNET_assert (NULL != label);
891 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
904 * Cancel a revocation.
906 * @param rh handle to the operation
909 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
911 GNUNET_assert (NULL != rh);
916 /*******************************
918 *******************************/
921 * Cleanup ticket consume handle
923 * @param cth the handle to clean up
926 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
928 struct ParallelLookup *lu;
930 if (NULL != cth->lookup_request)
931 GNUNET_GNS_lookup_cancel (cth->lookup_request);
932 if (NULL != cth->kill_task)
933 GNUNET_SCHEDULER_cancel (cth->kill_task);
934 while (NULL != (lu = cth->parallel_lookups_head))
936 if (NULL != lu->lookup_request)
937 GNUNET_GNS_lookup_cancel (lu->lookup_request);
938 GNUNET_free_non_null (lu->label);
939 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
940 cth->parallel_lookups_tail,
945 if (NULL != cth->attrs)
946 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cth->attrs);
952 * We found an attribute record.
954 * @param cls handle to the operation
955 * @param rd_cound size of record set
956 * @param rd record set
959 process_parallel_lookup_result (void *cls,
961 const struct GNUNET_GNSRECORD_Data *rd)
963 struct ParallelLookup *parallel_lookup = cls;
964 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
965 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
968 "Parallel lookup finished (count=%u)\n",
971 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
972 cth->parallel_lookups_tail,
974 GNUNET_free (parallel_lookup->label);
976 GNUNET_STATISTICS_update (stats,
977 "attribute_lookup_time_total",
978 GNUNET_TIME_absolute_get_duration (
979 parallel_lookup->lookup_start_time)
982 GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
985 GNUNET_free (parallel_lookup);
987 GNUNET_break (0); // FIXME: We should never find this.
988 if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR)
990 attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
992 GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
993 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
994 cth->attrs->list_tail,
998 if (NULL != cth->parallel_lookups_head)
999 return; // Wait for more
1001 /* Else we are done */
1002 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1008 * Cancel the lookups for attribute records
1010 * @param cls handle to the operation
1013 abort_parallel_lookups (void *cls)
1015 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1016 struct ParallelLookup *lu;
1017 struct ParallelLookup *tmp;
1019 cth->kill_task = NULL;
1020 for (lu = cth->parallel_lookups_head; NULL != lu;)
1022 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1023 GNUNET_free (lu->label);
1025 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1026 cth->parallel_lookups_tail,
1031 cth->cb (cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
1036 * GNS result with attribute references.
1037 * For each result, we start a (parallel) lookup of the actual
1038 * attribute record under the referenced label.
1040 * @param cls handle to the operation
1041 * @param rd_cound size of the record set
1042 * @param rd record set
1045 lookup_authz_cb (void *cls,
1047 const struct GNUNET_GNSRECORD_Data *rd)
1049 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1050 struct ParallelLookup *parallel_lookup;
1053 cth->lookup_request = NULL;
1055 GNUNET_STATISTICS_update (stats,
1056 "reclaim_authz_lookup_time_total",
1057 GNUNET_TIME_absolute_get_duration (
1058 cth->lookup_start_time)
1061 GNUNET_STATISTICS_update (stats,
1062 "reclaim_authz_lookups_count",
1066 for (int i = 0; i < rd_count; i++)
1068 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1070 lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
1071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
1072 parallel_lookup = GNUNET_new (struct ParallelLookup);
1073 parallel_lookup->handle = cth;
1074 parallel_lookup->label = lbl;
1075 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
1076 parallel_lookup->lookup_request =
1077 GNUNET_GNS_lookup (gns,
1079 &cth->ticket.identity,
1080 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
1081 GNUNET_GNS_LO_DEFAULT,
1082 &process_parallel_lookup_result,
1084 GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
1085 cth->parallel_lookups_tail,
1089 * We started lookups. Add a timeout task.
1090 * FIXME: Really needed here?
1092 if (NULL != cth->parallel_lookups_head)
1094 cth->kill_task = GNUNET_SCHEDULER_add_delayed (
1095 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
1096 &abort_parallel_lookups,
1101 * No references found, return empty attribute list
1103 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1110 * We first looking attribute references under the label
1111 * ticket.rnd in GNS.
1113 * @param id the audience of the ticket
1114 * @param ticket the ticket to consume
1115 * @param cb callback to call with attributes of ticket
1116 * @param cb_cls callback closure
1117 * @return handle to the operation
1119 struct RECLAIM_TICKETS_ConsumeHandle *
1120 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
1121 const struct GNUNET_RECLAIM_Ticket *ticket,
1122 RECLAIM_TICKETS_ConsumeCallback cb,
1125 struct RECLAIM_TICKETS_ConsumeHandle *cth;
1128 cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
1130 cth->identity = *id;
1131 GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
1132 cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1133 cth->ticket = *ticket;
1135 cth->cb_cls = cb_cls;
1137 GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof(uint64_t));
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "Looking for AuthZ info under %s\n",
1141 cth->lookup_start_time = GNUNET_TIME_absolute_get ();
1142 cth->lookup_request =
1143 GNUNET_GNS_lookup (gns,
1145 &cth->ticket.identity,
1146 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
1147 GNUNET_GNS_LO_DEFAULT,
1150 GNUNET_free (label);
1156 * Cancel a consume operation
1158 * @param cth the operation to cancel
1161 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
1168 /*******************************
1170 *******************************/
1173 * Cleanup ticket consume handle
1174 * @param handle the handle to clean up
1177 cleanup_issue_handle (struct TicketIssueHandle *handle)
1179 if (NULL != handle->ns_qe)
1180 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1181 GNUNET_free (handle);
1186 * Store finished, abort on error.
1187 * Else, return new ticket to caller.
1189 * @param cls handle to the operation
1190 * @param success store operation result
1191 * @param emsg error message (or NULL on success)
1194 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
1196 struct TicketIssueHandle *handle = cls;
1198 handle->ns_qe = NULL;
1199 if (GNUNET_SYSERR == success)
1201 handle->cb (handle->cb_cls,
1204 "Error storing AuthZ ticket in GNS");
1207 handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
1208 cleanup_issue_handle (handle);
1213 * Issue a new ticket.
1214 * We store references to attribute record labels and the ticket itself
1215 * under the label base64(ticket.rnd).
1217 * @param ih handle to the operation containing relevant metadata
1220 issue_ticket (struct TicketIssueHandle *ih)
1222 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1223 struct GNUNET_GNSRECORD_Data *attrs_record;
1225 size_t list_len = 1;
1228 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1232 GNUNET_malloc (list_len * sizeof(struct GNUNET_GNSRECORD_Data));
1234 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1236 attrs_record[i].data = &le->claim->id;
1237 attrs_record[i].data_size = sizeof(le->claim->id);
1239 * FIXME: Should this be the attribute expiration time or ticket
1240 * refresh interval? Probably min(attrs.expiration)
1242 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1243 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
1244 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1247 attrs_record[i].data = &ih->ticket;
1248 attrs_record[i].data_size = sizeof(struct GNUNET_RECLAIM_Ticket);
1249 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1250 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1251 attrs_record[i].flags =
1252 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1255 GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof(uint64_t));
1257 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1262 &store_ticket_issue_cont,
1264 GNUNET_free (attrs_record);
1265 GNUNET_free (label);
1268 /*************************************************
1269 * Ticket iteration (finding a specific ticket)
1270 *************************************************/
1274 * Namestore error on issue. Abort.
1276 * @param cls handle to the operation
1279 filter_tickets_error_cb (void *cls)
1281 struct TicketIssueHandle *tih = cls;
1284 tih->cb (tih->cb_cls,
1287 "Error storing AuthZ ticket in GNS");
1288 cleanup_issue_handle (tih);
1293 * Iterator over records.
1294 * Check if any previously issued ticket already
1295 * matches what we need to prevent duplicates and
1296 * improve resolution synergy.
1298 * @param cls handle to the operation
1299 * @param zone issuer identity
1300 * @param label ticket rnd
1301 * @param rd_count size of record set
1302 * @param rd record set
1305 filter_tickets_cb (void *cls,
1306 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1308 unsigned int rd_count,
1309 const struct GNUNET_GNSRECORD_Data *rd)
1311 struct TicketIssueHandle *tih = cls;
1312 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1314 // figure out the number of requested attributes
1315 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1316 unsigned int attr_cnt = 0;
1318 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1322 unsigned int found_attrs_cnt = 0;
1324 for (int i = 0; i < rd_count; i++)
1327 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
1329 ticket = (struct GNUNET_RECLAIM_Ticket *) rd[i].data;
1331 if (0 == memcmp (&tih->ticket.audience,
1333 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1335 tih->ticket = *ticket;
1341 // cmp requested attributes with ticket attributes
1342 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1344 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1346 // cmp attr_ref id with requested attr id
1347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1348 " %" PRIu64 "\n %" PRIu64 "\n",
1349 *((uint64_t *) rd[i].data),
1353 if (0 == memcmp (rd[i].data, &le->claim->id, sizeof(uint64_t)))
1359 * If we found a matching ticket, return that to the caller and
1362 if ((attr_cnt == found_attrs_cnt)&&(NULL != ticket))
1364 GNUNET_NAMESTORE_zone_iteration_stop (tih->ns_it);
1365 tih->cb (tih->cb_cls, &tih->ticket, GNUNET_OK, NULL);
1366 cleanup_issue_handle (tih);
1370 // ticket not found in current record, checking next record set
1371 GNUNET_NAMESTORE_zone_iterator_next (tih->ns_it, 1);
1376 * Done iterating over tickets and we apparently did
1377 * not find an existing, matching ticket.
1378 * Continue by issuing a new ticket.
1380 * @param cls handle to the operation
1383 filter_tickets_finished_cb (void *cls)
1385 struct TicketIssueHandle *tih = cls;
1387 GNUNET_CRYPTO_ecdsa_key_get_public (&tih->identity, &tih->ticket.identity);
1389 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
1395 * Issue a new reclaim ticket, thereby authorizing
1396 * the audience to access the set of provided attributes.
1398 * @param identity the issuer
1399 * @param attrs the attributes to share
1400 * @param audience the audience to share the attributes with
1401 * @param cb the callback to call with the ticket result
1402 * @param cb_cls the callback closure
1403 * FIXME: Return handle??
1406 RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1407 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1408 const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
1409 RECLAIM_TICKETS_TicketResult cb,
1412 struct TicketIssueHandle *tih;
1414 tih = GNUNET_new (struct TicketIssueHandle);
1416 tih->cb_cls = cb_cls;
1417 tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
1418 tih->identity = *identity;
1419 tih->ticket.audience = *audience;
1421 // First check whether the ticket has already been issued
1423 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1425 &filter_tickets_error_cb,
1429 &filter_tickets_finished_cb,
1434 /************************************
1436 ************************************/
1439 * Cleanup ticket iterator
1441 * @param iter handle to the iteration
1444 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
1446 if (NULL != iter->ns_it)
1447 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1453 * Return each record of type @GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET
1454 * to the caller and proceed with the iteration.
1455 * FIXME: Should we _not_ proceed automatically here?
1457 * @param cls handle to the iteration
1458 * @param zone the ticket issuer
1459 * @param label the ticket rnd
1460 * @param rd_count number of records in record set
1461 * @param rd record set containing a ticket
1464 collect_tickets_cb (void *cls,
1465 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1467 unsigned int rd_count,
1468 const struct GNUNET_GNSRECORD_Data *rd)
1470 struct RECLAIM_TICKETS_Iterator *iter = cls;
1472 for (int i = 0; i < rd_count; i++)
1474 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1476 iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *) rd[i].data);
1479 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1484 * Signal ticket iteration has finished
1486 * @param cls handle to the iteration
1489 collect_tickets_finished_cb (void *cls)
1491 struct RECLAIM_TICKETS_Iterator *iter = cls;
1494 iter->cb (iter->cb_cls, NULL);
1495 cleanup_iter (iter);
1500 * Cancel ticket iteration on namestore error
1502 * @param cls the iteration handle
1505 collect_tickets_error_cb (void *cls)
1507 struct RECLAIM_TICKETS_Iterator *iter = cls;
1510 iter->cb (iter->cb_cls, NULL);
1511 cleanup_iter (iter);
1516 * Continue ticket iteration
1518 * @param iter the iteration to continue
1521 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
1523 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1528 * Stop a running ticket iteration
1530 * @param iter iteration to cancel
1533 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
1535 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1536 cleanup_iter (iter);
1541 * Iterate over all tickets issued by an identity
1543 * @param identity the issuing identity
1544 * @param cb ticket callback function
1545 * @param cb_cls callback closure
1546 * @return a handle to the iteration
1548 struct RECLAIM_TICKETS_Iterator *
1549 RECLAIM_TICKETS_iteration_start (
1550 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1551 RECLAIM_TICKETS_TicketIter cb,
1554 struct RECLAIM_TICKETS_Iterator *iter;
1556 iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1558 iter->cb_cls = cb_cls;
1560 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1562 &collect_tickets_error_cb,
1564 &collect_tickets_cb,
1566 &collect_tickets_finished_cb,
1573 * Initialize tickets component
1575 * @param c the configuration
1576 * @return GNUNET_SYSERR on error
1579 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1581 // Get ticket expiration time (relative) from config
1583 GNUNET_CONFIGURATION_get_value_time (c,
1585 "TICKET_REFRESH_INTERVAL",
1586 &ticket_refresh_interval))
1588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1589 "Configured refresh interval for tickets: %s\n",
1590 GNUNET_STRINGS_relative_time_to_string (ticket_refresh_interval,
1595 ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1597 // Connect to identity and namestore services
1598 nsh = GNUNET_NAMESTORE_connect (c);
1601 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1602 "error connecting to namestore");
1603 return GNUNET_SYSERR;
1605 gns = GNUNET_GNS_connect (c);
1608 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1609 return GNUNET_SYSERR;
1611 stats = GNUNET_STATISTICS_create ("reclaim", c);
1617 * Close handles and clean up.
1618 * FIXME: cancel all pending operations (gns, ns etc)
1621 RECLAIM_TICKETS_deinit (void)
1624 GNUNET_NAMESTORE_disconnect (nsh);
1627 GNUNET_GNS_disconnect (gns);
1631 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);