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_RECLAIM_ATTRIBUTE_Claim *claim;
671 struct GNUNET_GNSRECORD_Data new_rd;
672 struct RevokedAttributeEntry *le;
679 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
680 "The attribute %s no longer exists!\n",
683 rvk->move_attr = le->next;
684 GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
686 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
689 /** find a new place for this attribute **/
690 rvk->move_attr->new_id =
691 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
693 claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
695 "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
698 claim->id = rvk->move_attr->new_id;
699 new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
700 attr_data = GNUNET_malloc (rd->data_size);
701 new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
702 new_rd.data = attr_data;
703 new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
706 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
713 GNUNET_free (new_label);
715 GNUNET_free (attr_data);
720 * We change every attribute ID of the ticket attributes we
722 * When we are done, we need to update any other ticket which
723 * included references to any of the changed attributes.
725 * @param rvk handle to the operation
728 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
732 if (NULL == rvk->move_attr)
734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
736 GNUNET_NAMESTORE_zone_iteration_start (nsh,
742 &rvk_ticket_update_finished,
746 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label);
750 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
762 * Finished deleting ticket and attribute references.
764 * Else, we start changing every attribute ID in the
765 * found attribute references so that access is no longer
768 * @param cls handle to the operation
769 * @param success Namestore operation return value
770 * @param emsg error message (NULL on success)
773 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
775 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
778 if (GNUNET_SYSERR == success)
780 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
781 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
786 if (0 == rvk->ticket_attrs)
788 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
789 "No attributes to move... strange\n");
790 rvk->cb (rvk->cb_cls, GNUNET_OK);
794 rvk->move_attr = rvk->attrs_head;
800 * We found the attribute references.
801 * Store them for later and remove the record set.
803 * @param cls handle to the operation
804 * @param zone the issuer key
805 * @param label ticket rnd
806 * @param rd_cound size of record set
807 * @param rd record set
810 revoke_attrs_cb (void *cls,
811 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
813 unsigned int rd_count,
814 const struct GNUNET_GNSRECORD_Data *rd)
817 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
818 struct RevokedAttributeEntry *le;
822 * Temporarily store attribute references.
825 for (int i = 0; i < rd_count; i++)
827 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
829 le = GNUNET_new (struct RevokedAttributeEntry);
830 le->old_id = *((uint64_t *) rd[i].data);
831 GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
835 /** Remove attribute references **/
836 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
847 * Failed to query namestore. Abort operation
849 * @param cls handle to the operation
852 rvk_attrs_err_cb (void *cls)
854 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
856 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
863 * We start by looking up attribute references in order
864 * to change attribute IDs.
866 * @param ticket ticket to revoke
867 * @param identity private key of issuer
868 * @param cb revocation status callback
869 * @param cb_cls callback closure
870 * @return handle to the operation
872 struct RECLAIM_TICKETS_RevokeHandle *
873 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
874 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
875 RECLAIM_TICKETS_RevokeCallback cb,
878 struct RECLAIM_TICKETS_RevokeHandle *rvk;
881 rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
883 rvk->cb_cls = cb_cls;
884 rvk->identity = *identity;
885 rvk->ticket = *ticket;
886 GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
887 /** Get shared attributes **/
888 label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
889 GNUNET_assert (NULL != label);
890 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
903 * Cancel a revocation.
905 * @param rh handle to the operation
908 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
910 GNUNET_assert (NULL != rh);
915 /*******************************
917 *******************************/
920 * Cleanup ticket consume handle
922 * @param cth the handle to clean up
925 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
927 struct ParallelLookup *lu;
929 if (NULL != cth->lookup_request)
930 GNUNET_GNS_lookup_cancel (cth->lookup_request);
931 if (NULL != cth->kill_task)
932 GNUNET_SCHEDULER_cancel (cth->kill_task);
933 while (NULL != (lu = cth->parallel_lookups_head))
935 if (NULL != lu->lookup_request)
936 GNUNET_GNS_lookup_cancel (lu->lookup_request);
937 GNUNET_free_non_null (lu->label);
938 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
939 cth->parallel_lookups_tail,
944 if (NULL != cth->attrs)
945 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cth->attrs);
951 * We found an attribute record.
953 * @param cls handle to the operation
954 * @param rd_cound size of record set
955 * @param rd record set
958 process_parallel_lookup_result (void *cls,
960 const struct GNUNET_GNSRECORD_Data *rd)
962 struct ParallelLookup *parallel_lookup = cls;
963 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
964 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
966 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
967 "Parallel lookup finished (count=%u)\n",
970 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
971 cth->parallel_lookups_tail,
973 GNUNET_free (parallel_lookup->label);
975 GNUNET_STATISTICS_update (stats,
976 "attribute_lookup_time_total",
977 GNUNET_TIME_absolute_get_duration (
978 parallel_lookup->lookup_start_time)
981 GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
984 GNUNET_free (parallel_lookup);
986 GNUNET_break (0); // FIXME: We should never find this.
987 if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR)
989 attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
991 GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
992 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
993 cth->attrs->list_tail,
997 if (NULL != cth->parallel_lookups_head)
998 return; // Wait for more
1000 /* Else we are done */
1001 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1007 * Cancel the lookups for attribute records
1009 * @param cls handle to the operation
1012 abort_parallel_lookups (void *cls)
1014 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1015 struct ParallelLookup *lu;
1016 struct ParallelLookup *tmp;
1018 cth->kill_task = NULL;
1019 for (lu = cth->parallel_lookups_head; NULL != lu;)
1021 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1022 GNUNET_free (lu->label);
1024 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1025 cth->parallel_lookups_tail,
1030 cth->cb (cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
1035 * GNS result with attribute references.
1036 * For each result, we start a (parallel) lookup of the actual
1037 * attribute record under the referenced label.
1039 * @param cls handle to the operation
1040 * @param rd_cound size of the record set
1041 * @param rd record set
1044 lookup_authz_cb (void *cls,
1046 const struct GNUNET_GNSRECORD_Data *rd)
1048 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1049 struct ParallelLookup *parallel_lookup;
1052 cth->lookup_request = NULL;
1054 GNUNET_STATISTICS_update (stats,
1055 "reclaim_authz_lookup_time_total",
1056 GNUNET_TIME_absolute_get_duration (
1057 cth->lookup_start_time)
1060 GNUNET_STATISTICS_update (stats,
1061 "reclaim_authz_lookups_count",
1065 for (int i = 0; i < rd_count; i++)
1067 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1069 lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
1070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
1071 parallel_lookup = GNUNET_new (struct ParallelLookup);
1072 parallel_lookup->handle = cth;
1073 parallel_lookup->label = lbl;
1074 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
1075 parallel_lookup->lookup_request =
1076 GNUNET_GNS_lookup (gns,
1078 &cth->ticket.identity,
1079 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
1080 GNUNET_GNS_LO_DEFAULT,
1081 &process_parallel_lookup_result,
1083 GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
1084 cth->parallel_lookups_tail,
1088 * We started lookups. Add a timeout task.
1089 * FIXME: Really needed here?
1091 if (NULL != cth->parallel_lookups_head)
1093 cth->kill_task = GNUNET_SCHEDULER_add_delayed (
1094 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
1095 &abort_parallel_lookups,
1100 * No references found, return empty attribute list
1102 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1109 * We first looking attribute references under the label
1110 * ticket.rnd in GNS.
1112 * @param id the audience of the ticket
1113 * @param ticket the ticket to consume
1114 * @param cb callback to call with attributes of ticket
1115 * @param cb_cls callback closure
1116 * @return handle to the operation
1118 struct RECLAIM_TICKETS_ConsumeHandle *
1119 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
1120 const struct GNUNET_RECLAIM_Ticket *ticket,
1121 RECLAIM_TICKETS_ConsumeCallback cb,
1124 struct RECLAIM_TICKETS_ConsumeHandle *cth;
1127 cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
1129 cth->identity = *id;
1130 GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
1131 cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1132 cth->ticket = *ticket;
1134 cth->cb_cls = cb_cls;
1136 GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof(uint64_t));
1137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1138 "Looking for AuthZ info under %s\n",
1140 cth->lookup_start_time = GNUNET_TIME_absolute_get ();
1141 cth->lookup_request =
1142 GNUNET_GNS_lookup (gns,
1144 &cth->ticket.identity,
1145 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
1146 GNUNET_GNS_LO_DEFAULT,
1149 GNUNET_free (label);
1155 * Cancel a consume operation
1157 * @param cth the operation to cancel
1160 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
1167 /*******************************
1169 *******************************/
1172 * Cleanup ticket consume handle
1173 * @param handle the handle to clean up
1176 cleanup_issue_handle (struct TicketIssueHandle *handle)
1178 if (NULL != handle->ns_qe)
1179 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1180 GNUNET_free (handle);
1185 * Store finished, abort on error.
1186 * Else, return new ticket to caller.
1188 * @param cls handle to the operation
1189 * @param success store operation result
1190 * @param emsg error message (or NULL on success)
1193 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
1195 struct TicketIssueHandle *handle = cls;
1197 handle->ns_qe = NULL;
1198 if (GNUNET_SYSERR == success)
1200 handle->cb (handle->cb_cls,
1203 "Error storing AuthZ ticket in GNS");
1206 handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
1207 cleanup_issue_handle (handle);
1212 * Issue a new ticket.
1213 * We store references to attribute record labels and the ticket itself
1214 * under the label base64(ticket.rnd).
1216 * @param ih handle to the operation containing relevant metadata
1219 issue_ticket (struct TicketIssueHandle *ih)
1221 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1222 struct GNUNET_GNSRECORD_Data *attrs_record;
1224 size_t list_len = 1;
1227 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1231 GNUNET_malloc (list_len * sizeof(struct GNUNET_GNSRECORD_Data));
1233 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1235 attrs_record[i].data = &le->claim->id;
1236 attrs_record[i].data_size = sizeof(le->claim->id);
1238 * FIXME: Should this be the attribute expiration time or ticket
1239 * refresh interval? Probably min(attrs.expiration)
1241 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1242 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
1243 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1246 attrs_record[i].data = &ih->ticket;
1247 attrs_record[i].data_size = sizeof(struct GNUNET_RECLAIM_Ticket);
1248 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1249 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1250 attrs_record[i].flags =
1251 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1254 GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof(uint64_t));
1256 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1261 &store_ticket_issue_cont,
1263 GNUNET_free (attrs_record);
1264 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);