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 {
51 struct TicketReference *next;
56 struct TicketReference *prev;
61 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
66 struct GNUNET_RECLAIM_Ticket ticket;
71 * Handle to a consume operation
73 struct RECLAIM_TICKETS_ConsumeHandle {
77 struct GNUNET_RECLAIM_Ticket ticket;
82 struct GNUNET_GNS_LookupRequest *lookup_request;
87 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
92 struct GNUNET_CRYPTO_EcdsaPublicKey identity_pub;
97 struct ParallelLookup *parallel_lookups_head;
102 struct ParallelLookup *parallel_lookups_tail;
107 struct GNUNET_SCHEDULER_Task *kill_task;
112 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
117 struct GNUNET_TIME_Absolute lookup_start_time;
122 RECLAIM_TICKETS_ConsumeCallback cb;
132 * Handle for a parallel GNS lookup job
134 struct ParallelLookup {
136 struct ParallelLookup *next;
139 struct ParallelLookup *prev;
141 /* The GNS request */
142 struct GNUNET_GNS_LookupRequest *lookup_request;
144 /* The handle the return to */
145 struct RECLAIM_TICKETS_ConsumeHandle *handle;
150 struct GNUNET_TIME_Absolute lookup_start_time;
152 /* The label to look up */
158 * Ticket issue request handle
160 struct TicketIssueHandle {
162 * Attributes to issue
164 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs;
169 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
174 struct GNUNET_RECLAIM_Ticket ticket;
179 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
184 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
189 RECLAIM_TICKETS_TicketResult cb;
201 struct RECLAIM_TICKETS_Iterator {
203 * Namestore queue entry
205 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
210 RECLAIM_TICKETS_TicketIter cb;
219 struct RevokedAttributeEntry {
223 struct RevokedAttributeEntry *next;
228 struct RevokedAttributeEntry *prev;
231 * Old ID of the attribute
236 * New ID of the attribute
243 * Ticket revocation request handle
245 struct RECLAIM_TICKETS_RevokeHandle {
249 struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
254 RECLAIM_TICKETS_RevokeCallback cb;
264 struct GNUNET_RECLAIM_Ticket ticket;
269 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
274 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
279 struct RevokedAttributeEntry *attrs_head;
284 struct RevokedAttributeEntry *attrs_tail;
287 * Current attribute to move
289 struct RevokedAttributeEntry *move_attr;
292 * Number of attributes in ticket
294 unsigned int ticket_attrs;
299 struct TicketRecordsEntry *tickets_to_update_head;
304 struct TicketRecordsEntry *tickets_to_update_tail;
309 * Ticket expiration interval
311 static struct GNUNET_TIME_Relative ticket_refresh_interval;
314 /* Namestore handle */
315 static struct GNUNET_NAMESTORE_Handle *nsh;
319 static struct GNUNET_GNS_Handle *gns;
322 /* Handle to the statistics service */
323 static struct GNUNET_STATISTICS_Handle *stats;
328 * Cleanup revoke handle
330 * @param rh the ticket revocation handle
333 cleanup_rvk(struct RECLAIM_TICKETS_RevokeHandle *rh)
335 struct RevokedAttributeEntry *ae;
336 struct TicketRecordsEntry *le;
338 if (NULL != rh->ns_qe)
339 GNUNET_NAMESTORE_cancel(rh->ns_qe);
340 if (NULL != rh->ns_it)
341 GNUNET_NAMESTORE_zone_iteration_stop(rh->ns_it);
342 while (NULL != (ae = rh->attrs_head))
344 GNUNET_CONTAINER_DLL_remove(rh->attrs_head, rh->attrs_tail, ae);
347 while (NULL != (le = rh->tickets_to_update_head))
349 GNUNET_CONTAINER_DLL_remove(rh->tickets_to_update_head,
350 rh->tickets_to_update_head,
352 if (NULL != le->data)
353 GNUNET_free(le->data);
354 if (NULL != le->label)
355 GNUNET_free(le->label);
363 * For each ticket, store new, updated attribute references
364 * (Implementation further below)
366 * @param cls handle to the operation
369 process_tickets(void *cls);
373 * Finished storing updated attribute references.
374 * Abort on error, else continue processing tickets
376 * @param cls handle to the operation
377 * @param success result of namestore operation
378 * @param emsg (NULL on success)
381 ticket_processed(void *cls, int32_t success, const char *emsg)
383 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
386 GNUNET_SCHEDULER_add_now(&process_tickets, rvk);
391 * For each ticket, store new, updated attribute references
393 * @param cls handle to the operation
396 process_tickets(void *cls)
398 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
399 struct TicketRecordsEntry *le;
400 struct RevokedAttributeEntry *ae;
402 if (NULL == rvk->tickets_to_update_head)
404 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
405 "Finished updatding tickets, success\n");
406 rvk->cb(rvk->cb_cls, GNUNET_OK);
410 le = rvk->tickets_to_update_head;
411 GNUNET_CONTAINER_DLL_remove(rvk->tickets_to_update_head,
412 rvk->tickets_to_update_tail,
414 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
415 if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize(le->data_size,
420 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
421 "Unable to deserialize ticket record(s)\n");
422 rvk->cb(rvk->cb_cls, GNUNET_SYSERR);
426 for (int i = 0; i < le->rd_count; i++)
428 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
430 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
432 if (0 != memcmp(rd[i].data, &ae->old_id, sizeof(uint64_t)))
434 rd[i].data = &ae->new_id;
437 rvk->ns_qe = GNUNET_NAMESTORE_records_store(nsh,
444 GNUNET_free(le->label);
445 GNUNET_free(le->data);
451 * Done collecting tickets. Start processing.
453 * @param cls handle to the operation
456 rvk_ticket_update_finished(void *cls)
458 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
461 GNUNET_SCHEDULER_add_now(&process_tickets, rvk);
466 * We need to update all other tickets with the new attribute IDs.
467 * We first collect them all. Processing after.
469 * @param cls handle to the operation
470 * @param zone ticket issuer private key
471 * @param label ticket rnd
472 * @param rd_cound size of record set
473 * @param rd record set
476 rvk_ticket_update(void *cls,
477 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
479 unsigned int rd_count,
480 const struct GNUNET_GNSRECORD_Data *rd)
482 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
483 struct TicketRecordsEntry *le;
484 struct RevokedAttributeEntry *ae;
485 int has_changed = GNUNET_NO;
487 /** Let everything point to the old record **/
488 for (int i = 0; i < rd_count; i++)
490 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
492 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
494 if (0 != memcmp(rd[i].data, &ae->old_id, sizeof(uint64_t)))
496 has_changed = GNUNET_YES;
499 if (GNUNET_YES == has_changed)
502 if (GNUNET_YES == has_changed)
504 le = GNUNET_new(struct TicketRecordsEntry);
505 le->data_size = GNUNET_GNSRECORD_records_get_size(rd_count, rd);
506 le->data = GNUNET_malloc(le->data_size);
507 le->rd_count = rd_count;
508 le->label = GNUNET_strdup(label);
509 GNUNET_GNSRECORD_records_serialize(rd_count, rd, le->data_size, le->data);
510 GNUNET_CONTAINER_DLL_insert(rvk->tickets_to_update_head,
511 rvk->tickets_to_update_tail,
514 GNUNET_NAMESTORE_zone_iterator_next(rvk->ns_it, 1);
519 * Error iterating namestore. Abort.
521 * @param cls handle to the operation
524 rvk_ns_iter_err(void *cls)
526 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
529 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
530 "Namestore error on revocation (id=%" PRIu64 "\n",
531 rvk->move_attr->old_id);
532 rvk->cb(rvk->cb_cls, GNUNET_SYSERR);
538 * Error storing new attribute in namestore. Abort
540 * @param cls handle to the operation
543 rvk_ns_err(void *cls)
545 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
548 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
549 "Namestore error on revocation (id=%" PRIu64 "\n",
550 rvk->move_attr->old_id);
551 rvk->cb(rvk->cb_cls, GNUNET_SYSERR);
557 * We change every attribute ID of the ticket attributes we
559 * When we are done, we need to update any other ticket which
560 * included references to any of the changed attributes.
561 * (Implementation further below)
563 * @param rvk handle to the operation
566 move_attrs(struct RECLAIM_TICKETS_RevokeHandle *rh);
570 * Delayed continuation for move_attrs
572 * @param cls handle to the operation.
575 move_attrs_cont(void *cls)
577 move_attrs((struct RECLAIM_TICKETS_RevokeHandle *)cls);
582 * Done deleting the old record. Abort on error.
583 * Else, continue updating attribute IDs.
585 * @param cls handle to the operation
586 * @param success result of the namestore operation
587 * @param emsg error message (NULL on success)
590 del_attr_finished(void *cls, int32_t success, const char *emsg)
592 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
595 if (GNUNET_SYSERR == success)
597 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
598 "Error removing attribute: %s\n",
600 rvk->cb(rvk->cb_cls, GNUNET_SYSERR);
604 rvk->move_attr = rvk->move_attr->next;
605 GNUNET_SCHEDULER_add_now(&move_attrs_cont, rvk);
610 * Updated an attribute ID.
611 * Abort on error if namestore operation failed.
612 * Else, we have to delete the old record.
614 * @param cls handle to the operation
615 * @param success result of the store operation
616 * @param emsg error message (NULL on success)
619 move_attr_finished(void *cls, int32_t success, const char *emsg)
621 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
625 if (GNUNET_SYSERR == success)
627 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
628 rvk->cb(rvk->cb_cls, GNUNET_SYSERR);
632 label = GNUNET_STRINGS_data_to_string_alloc(&rvk->move_attr->old_id,
634 GNUNET_assert(NULL != label);
635 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
636 rvk->ns_qe = GNUNET_NAMESTORE_records_store(nsh,
648 * Got the referenced attribute. Updating the ID
650 * @param cls handle to the operation
651 * @param zone issuer identity
652 * @param label attribute ID
653 * @param rd_count size of record set (should be 1)
654 * @param rd record set (the attribute)
657 rvk_move_attr_cb(void *cls,
658 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
660 unsigned int rd_count,
661 const struct GNUNET_GNSRECORD_Data *rd)
663 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
664 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
665 struct GNUNET_GNSRECORD_Data new_rd;
666 struct RevokedAttributeEntry *le;
673 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
674 "The attribute %s no longer exists!\n",
677 rvk->move_attr = le->next;
678 GNUNET_CONTAINER_DLL_remove(rvk->attrs_head, rvk->attrs_tail, le);
680 GNUNET_SCHEDULER_add_now(&move_attrs_cont, rvk);
683 /** find a new place for this attribute **/
684 rvk->move_attr->new_id =
685 GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
687 claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize(rd->data, rd->data_size);
688 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
689 "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
692 claim->id = rvk->move_attr->new_id;
693 new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size(claim);
694 attr_data = GNUNET_malloc(rd->data_size);
695 new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize(claim, attr_data);
696 new_rd.data = attr_data;
697 new_label = GNUNET_STRINGS_data_to_string_alloc(&rvk->move_attr->new_id,
699 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
700 rvk->ns_qe = GNUNET_NAMESTORE_records_store(nsh,
707 GNUNET_free(new_label);
709 GNUNET_free(attr_data);
714 * We change every attribute ID of the ticket attributes we
716 * When we are done, we need to update any other ticket which
717 * included references to any of the changed attributes.
719 * @param rvk handle to the operation
722 move_attrs(struct RECLAIM_TICKETS_RevokeHandle *rvk)
726 if (NULL == rvk->move_attr)
728 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
730 GNUNET_NAMESTORE_zone_iteration_start(nsh,
736 &rvk_ticket_update_finished,
740 label = GNUNET_STRINGS_data_to_string_alloc(&rvk->move_attr->old_id,
742 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label);
744 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup(nsh,
756 * Finished deleting ticket and attribute references.
758 * Else, we start changing every attribute ID in the
759 * found attribute references so that access is no longer
762 * @param cls handle to the operation
763 * @param success Namestore operation return value
764 * @param emsg error message (NULL on success)
767 remove_ticket_cont(void *cls, int32_t success, const char *emsg)
769 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
772 if (GNUNET_SYSERR == success)
774 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
775 rvk->cb(rvk->cb_cls, GNUNET_SYSERR);
779 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
780 if (0 == rvk->ticket_attrs)
782 GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
783 "No attributes to move... strange\n");
784 rvk->cb(rvk->cb_cls, GNUNET_OK);
788 rvk->move_attr = rvk->attrs_head;
794 * We found the attribute references.
795 * Store them for later and remove the record set.
797 * @param cls handle to the operation
798 * @param zone the issuer key
799 * @param label ticket rnd
800 * @param rd_cound size of record set
801 * @param rd record set
804 revoke_attrs_cb(void *cls,
805 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
807 unsigned int rd_count,
808 const struct GNUNET_GNSRECORD_Data *rd)
811 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
812 struct RevokedAttributeEntry *le;
816 * Temporarily store attribute references.
819 for (int i = 0; i < rd_count; i++)
821 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
823 le = GNUNET_new(struct RevokedAttributeEntry);
824 le->old_id = *((uint64_t *)rd[i].data);
825 GNUNET_CONTAINER_DLL_insert(rvk->attrs_head, rvk->attrs_tail, le);
829 /** Remove attribute references **/
830 rvk->ns_qe = GNUNET_NAMESTORE_records_store(nsh,
841 * Failed to query namestore. Abort operation
843 * @param cls handle to the operation
846 rvk_attrs_err_cb(void *cls)
848 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
850 rvk->cb(rvk->cb_cls, GNUNET_SYSERR);
857 * We start by looking up attribute references in order
858 * to change attribute IDs.
860 * @param ticket ticket to revoke
861 * @param identity private key of issuer
862 * @param cb revocation status callback
863 * @param cb_cls callback closure
864 * @return handle to the operation
866 struct RECLAIM_TICKETS_RevokeHandle *
867 RECLAIM_TICKETS_revoke(const struct GNUNET_RECLAIM_Ticket *ticket,
868 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
869 RECLAIM_TICKETS_RevokeCallback cb,
872 struct RECLAIM_TICKETS_RevokeHandle *rvk;
875 rvk = GNUNET_new(struct RECLAIM_TICKETS_RevokeHandle);
877 rvk->cb_cls = cb_cls;
878 rvk->identity = *identity;
879 rvk->ticket = *ticket;
880 GNUNET_CRYPTO_ecdsa_key_get_public(&rvk->identity, &rvk->ticket.identity);
881 /** Get shared attributes **/
882 label = GNUNET_STRINGS_data_to_string_alloc(&ticket->rnd, sizeof(uint64_t));
883 GNUNET_assert(NULL != label);
884 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup(nsh,
897 * Cancel a revocation.
899 * @param rh handle to the operation
902 RECLAIM_TICKETS_revoke_cancel(struct RECLAIM_TICKETS_RevokeHandle *rh)
904 GNUNET_assert(NULL != rh);
909 /*******************************
911 *******************************/
914 * Cleanup ticket consume handle
916 * @param cth the handle to clean up
919 cleanup_cth(struct RECLAIM_TICKETS_ConsumeHandle *cth)
921 struct ParallelLookup *lu;
923 if (NULL != cth->lookup_request)
924 GNUNET_GNS_lookup_cancel(cth->lookup_request);
925 if (NULL != cth->kill_task)
926 GNUNET_SCHEDULER_cancel(cth->kill_task);
927 while (NULL != (lu = cth->parallel_lookups_head))
929 if (NULL != lu->lookup_request)
930 GNUNET_GNS_lookup_cancel(lu->lookup_request);
931 GNUNET_free_non_null(lu->label);
932 GNUNET_CONTAINER_DLL_remove(cth->parallel_lookups_head,
933 cth->parallel_lookups_tail,
938 if (NULL != cth->attrs)
939 GNUNET_RECLAIM_ATTRIBUTE_list_destroy(cth->attrs);
945 * We found an attribute record.
947 * @param cls handle to the operation
948 * @param rd_cound size of record set
949 * @param rd record set
952 process_parallel_lookup_result(void *cls,
954 const struct GNUNET_GNSRECORD_Data *rd)
956 struct ParallelLookup *parallel_lookup = cls;
957 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
958 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
960 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
961 "Parallel lookup finished (count=%u)\n",
964 GNUNET_CONTAINER_DLL_remove(cth->parallel_lookups_head,
965 cth->parallel_lookups_tail,
967 GNUNET_free(parallel_lookup->label);
969 GNUNET_STATISTICS_update(stats,
970 "attribute_lookup_time_total",
971 GNUNET_TIME_absolute_get_duration(
972 parallel_lookup->lookup_start_time)
975 GNUNET_STATISTICS_update(stats, "attribute_lookups_count", 1, GNUNET_YES);
978 GNUNET_free(parallel_lookup);
980 GNUNET_break(0); // FIXME: We should never find this.
981 if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR)
983 attr_le = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
985 GNUNET_RECLAIM_ATTRIBUTE_deserialize(rd->data, rd->data_size);
986 GNUNET_CONTAINER_DLL_insert(cth->attrs->list_head,
987 cth->attrs->list_tail,
991 if (NULL != cth->parallel_lookups_head)
992 return; // Wait for more
994 /* Else we are done */
995 cth->cb(cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1001 * Cancel the lookups for attribute records
1003 * @param cls handle to the operation
1006 abort_parallel_lookups(void *cls)
1008 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1009 struct ParallelLookup *lu;
1010 struct ParallelLookup *tmp;
1012 cth->kill_task = NULL;
1013 for (lu = cth->parallel_lookups_head; NULL != lu;)
1015 GNUNET_GNS_lookup_cancel(lu->lookup_request);
1016 GNUNET_free(lu->label);
1018 GNUNET_CONTAINER_DLL_remove(cth->parallel_lookups_head,
1019 cth->parallel_lookups_tail,
1024 cth->cb(cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
1029 * GNS result with attribute references.
1030 * For each result, we start a (parallel) lookup of the actual
1031 * attribute record under the referenced label.
1033 * @param cls handle to the operation
1034 * @param rd_cound size of the record set
1035 * @param rd record set
1038 lookup_authz_cb(void *cls,
1040 const struct GNUNET_GNSRECORD_Data *rd)
1042 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1043 struct ParallelLookup *parallel_lookup;
1046 cth->lookup_request = NULL;
1048 GNUNET_STATISTICS_update(stats,
1049 "reclaim_authz_lookup_time_total",
1050 GNUNET_TIME_absolute_get_duration(
1051 cth->lookup_start_time)
1054 GNUNET_STATISTICS_update(stats,
1055 "reclaim_authz_lookups_count",
1059 for (int i = 0; i < rd_count; i++)
1061 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1063 lbl = GNUNET_STRINGS_data_to_string_alloc(rd[i].data, rd[i].data_size);
1064 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
1065 parallel_lookup = GNUNET_new(struct ParallelLookup);
1066 parallel_lookup->handle = cth;
1067 parallel_lookup->label = lbl;
1068 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get();
1069 parallel_lookup->lookup_request =
1070 GNUNET_GNS_lookup(gns,
1072 &cth->ticket.identity,
1073 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
1074 GNUNET_GNS_LO_DEFAULT,
1075 &process_parallel_lookup_result,
1077 GNUNET_CONTAINER_DLL_insert(cth->parallel_lookups_head,
1078 cth->parallel_lookups_tail,
1082 * We started lookups. Add a timeout task.
1083 * FIXME: Really needed here?
1085 if (NULL != cth->parallel_lookups_head)
1087 cth->kill_task = GNUNET_SCHEDULER_add_delayed(
1088 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MINUTES, 3),
1089 &abort_parallel_lookups,
1094 * No references found, return empty attribute list
1096 cth->cb(cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1103 * We first looking attribute references under the label
1104 * ticket.rnd in GNS.
1106 * @param id the audience of the ticket
1107 * @param ticket the ticket to consume
1108 * @param cb callback to call with attributes of ticket
1109 * @param cb_cls callback closure
1110 * @return handle to the operation
1112 struct RECLAIM_TICKETS_ConsumeHandle *
1113 RECLAIM_TICKETS_consume(const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
1114 const struct GNUNET_RECLAIM_Ticket *ticket,
1115 RECLAIM_TICKETS_ConsumeCallback cb,
1118 struct RECLAIM_TICKETS_ConsumeHandle *cth;
1121 cth = GNUNET_new(struct RECLAIM_TICKETS_ConsumeHandle);
1123 cth->identity = *id;
1124 GNUNET_CRYPTO_ecdsa_key_get_public(&cth->identity, &cth->identity_pub);
1125 cth->attrs = GNUNET_new(struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1126 cth->ticket = *ticket;
1128 cth->cb_cls = cb_cls;
1130 GNUNET_STRINGS_data_to_string_alloc(&cth->ticket.rnd, sizeof(uint64_t));
1131 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1132 "Looking for AuthZ info under %s\n",
1134 cth->lookup_start_time = GNUNET_TIME_absolute_get();
1135 cth->lookup_request =
1136 GNUNET_GNS_lookup(gns,
1138 &cth->ticket.identity,
1139 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
1140 GNUNET_GNS_LO_DEFAULT,
1149 * Cancel a consume operation
1151 * @param cth the operation to cancel
1154 RECLAIM_TICKETS_consume_cancel(struct RECLAIM_TICKETS_ConsumeHandle *cth)
1161 /*******************************
1163 *******************************/
1166 * Cleanup ticket consume handle
1167 * @param handle the handle to clean up
1170 cleanup_issue_handle(struct TicketIssueHandle *handle)
1172 if (NULL != handle->ns_qe)
1173 GNUNET_NAMESTORE_cancel(handle->ns_qe);
1174 GNUNET_free(handle);
1179 * Store finished, abort on error.
1180 * Else, return new ticket to caller.
1182 * @param cls handle to the operation
1183 * @param success store operation result
1184 * @param emsg error message (or NULL on success)
1187 store_ticket_issue_cont(void *cls, int32_t success, const char *emsg)
1189 struct TicketIssueHandle *handle = cls;
1191 handle->ns_qe = NULL;
1192 if (GNUNET_SYSERR == success)
1194 handle->cb(handle->cb_cls,
1197 "Error storing AuthZ ticket in GNS");
1200 handle->cb(handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
1201 cleanup_issue_handle(handle);
1206 * Issue a new ticket.
1207 * We store references to attribute record labels and the ticket itself
1208 * under the label base64(ticket.rnd).
1210 * @param ih handle to the operation containing relevant metadata
1213 issue_ticket(struct TicketIssueHandle *ih)
1215 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1216 struct GNUNET_GNSRECORD_Data *attrs_record;
1218 size_t list_len = 1;
1221 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1225 GNUNET_malloc(list_len * sizeof(struct GNUNET_GNSRECORD_Data));
1227 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1229 attrs_record[i].data = &le->claim->id;
1230 attrs_record[i].data_size = sizeof(le->claim->id);
1232 * FIXME: Should this be the attribute expiration time or ticket
1233 * refresh interval? Probably min(attrs.expiration)
1235 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1236 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
1237 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1240 attrs_record[i].data = &ih->ticket;
1241 attrs_record[i].data_size = sizeof(struct GNUNET_RECLAIM_Ticket);
1242 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1243 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1244 attrs_record[i].flags =
1245 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1248 GNUNET_STRINGS_data_to_string_alloc(&ih->ticket.rnd, sizeof(uint64_t));
1250 ih->ns_qe = GNUNET_NAMESTORE_records_store(nsh,
1255 &store_ticket_issue_cont,
1257 GNUNET_free(attrs_record);
1261 /*************************************************
1262 * Ticket iteration (finding a specific ticket)
1263 *************************************************/
1267 * Namestore error on issue. Abort.
1269 * @param cls handle to the operation
1272 filter_tickets_error_cb(void *cls)
1274 struct TicketIssueHandle *tih = cls;
1277 tih->cb(tih->cb_cls,
1280 "Error storing AuthZ ticket in GNS");
1281 cleanup_issue_handle(tih);
1286 * Iterator over records.
1287 * Check if any previously issued ticket already
1288 * matches what we need to prevent duplicates and
1289 * improve resolution synergy.
1291 * @param cls handle to the operation
1292 * @param zone issuer identity
1293 * @param label ticket rnd
1294 * @param rd_count size of record set
1295 * @param rd record set
1298 filter_tickets_cb(void *cls,
1299 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1301 unsigned int rd_count,
1302 const struct GNUNET_GNSRECORD_Data *rd)
1304 struct TicketIssueHandle *tih = cls;
1305 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1307 // figure out the number of requested attributes
1308 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1309 unsigned int attr_cnt = 0;
1311 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1315 unsigned int found_attrs_cnt = 0;
1317 for (int i = 0; i < rd_count; i++)
1320 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
1322 ticket = (struct GNUNET_RECLAIM_Ticket *)rd[i].data;
1324 if (0 == memcmp(&tih->ticket.audience,
1326 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)))
1328 tih->ticket = *ticket;
1334 // cmp requested attributes with ticket attributes
1335 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1337 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1339 // cmp attr_ref id with requested attr id
1340 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1341 " %" PRIu64 "\n %" PRIu64 "\n",
1342 *((uint64_t *)rd[i].data),
1346 if (0 == memcmp(rd[i].data, &le->claim->id, sizeof(uint64_t)))
1352 * If we found a matching ticket, return that to the caller and
1355 if (attr_cnt == found_attrs_cnt && NULL != ticket)
1357 GNUNET_NAMESTORE_zone_iteration_stop(tih->ns_it);
1358 tih->cb(tih->cb_cls, &tih->ticket, GNUNET_OK, NULL);
1359 cleanup_issue_handle(tih);
1363 // ticket not found in current record, checking next record set
1364 GNUNET_NAMESTORE_zone_iterator_next(tih->ns_it, 1);
1369 * Done iterating over tickets and we apparently did
1370 * not find an existing, matching ticket.
1371 * Continue by issuing a new ticket.
1373 * @param cls handle to the operation
1376 filter_tickets_finished_cb(void *cls)
1378 struct TicketIssueHandle *tih = cls;
1380 GNUNET_CRYPTO_ecdsa_key_get_public(&tih->identity, &tih->ticket.identity);
1382 GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
1388 * Issue a new reclaim ticket, thereby authorizing
1389 * the audience to access the set of provided attributes.
1391 * @param identity the issuer
1392 * @param attrs the attributes to share
1393 * @param audience the audience to share the attributes with
1394 * @param cb the callback to call with the ticket result
1395 * @param cb_cls the callback closure
1396 * FIXME: Return handle??
1399 RECLAIM_TICKETS_issue(const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1400 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1401 const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
1402 RECLAIM_TICKETS_TicketResult cb,
1405 struct TicketIssueHandle *tih;
1407 tih = GNUNET_new(struct TicketIssueHandle);
1409 tih->cb_cls = cb_cls;
1410 tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup(attrs);
1411 tih->identity = *identity;
1412 tih->ticket.audience = *audience;
1414 // First check whether the ticket has already been issued
1416 GNUNET_NAMESTORE_zone_iteration_start(nsh,
1418 &filter_tickets_error_cb,
1422 &filter_tickets_finished_cb,
1427 /************************************
1429 ************************************/
1432 * Cleanup ticket iterator
1434 * @param iter handle to the iteration
1437 cleanup_iter(struct RECLAIM_TICKETS_Iterator *iter)
1439 if (NULL != iter->ns_it)
1440 GNUNET_NAMESTORE_zone_iteration_stop(iter->ns_it);
1446 * Return each record of type @GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET
1447 * to the caller and proceed with the iteration.
1448 * FIXME: Should we _not_ proceed automatically here?
1450 * @param cls handle to the iteration
1451 * @param zone the ticket issuer
1452 * @param label the ticket rnd
1453 * @param rd_count number of records in record set
1454 * @param rd record set containing a ticket
1457 collect_tickets_cb(void *cls,
1458 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1460 unsigned int rd_count,
1461 const struct GNUNET_GNSRECORD_Data *rd)
1463 struct RECLAIM_TICKETS_Iterator *iter = cls;
1465 for (int i = 0; i < rd_count; i++)
1467 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1469 iter->cb(iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *)rd[i].data);
1472 GNUNET_NAMESTORE_zone_iterator_next(iter->ns_it, 1);
1477 * Signal ticket iteration has finished
1479 * @param cls handle to the iteration
1482 collect_tickets_finished_cb(void *cls)
1484 struct RECLAIM_TICKETS_Iterator *iter = cls;
1487 iter->cb(iter->cb_cls, NULL);
1493 * Cancel ticket iteration on namestore error
1495 * @param cls the iteration handle
1498 collect_tickets_error_cb(void *cls)
1500 struct RECLAIM_TICKETS_Iterator *iter = cls;
1503 iter->cb(iter->cb_cls, NULL);
1509 * Continue ticket iteration
1511 * @param iter the iteration to continue
1514 RECLAIM_TICKETS_iteration_next(struct RECLAIM_TICKETS_Iterator *iter)
1516 GNUNET_NAMESTORE_zone_iterator_next(iter->ns_it, 1);
1521 * Stop a running ticket iteration
1523 * @param iter iteration to cancel
1526 RECLAIM_TICKETS_iteration_stop(struct RECLAIM_TICKETS_Iterator *iter)
1528 GNUNET_NAMESTORE_zone_iteration_stop(iter->ns_it);
1534 * Iterate over all tickets issued by an identity
1536 * @param identity the issuing identity
1537 * @param cb ticket callback function
1538 * @param cb_cls callback closure
1539 * @return a handle to the iteration
1541 struct RECLAIM_TICKETS_Iterator *
1542 RECLAIM_TICKETS_iteration_start(
1543 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1544 RECLAIM_TICKETS_TicketIter cb,
1547 struct RECLAIM_TICKETS_Iterator *iter;
1549 iter = GNUNET_new(struct RECLAIM_TICKETS_Iterator);
1551 iter->cb_cls = cb_cls;
1553 GNUNET_NAMESTORE_zone_iteration_start(nsh,
1555 &collect_tickets_error_cb,
1557 &collect_tickets_cb,
1559 &collect_tickets_finished_cb,
1566 * Initialize tickets component
1568 * @param c the configuration
1569 * @return GNUNET_SYSERR on error
1572 RECLAIM_TICKETS_init(const struct GNUNET_CONFIGURATION_Handle *c)
1574 // Get ticket expiration time (relative) from config
1576 GNUNET_CONFIGURATION_get_value_time(c,
1578 "TICKET_REFRESH_INTERVAL",
1579 &ticket_refresh_interval))
1581 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
1582 "Configured refresh interval for tickets: %s\n",
1583 GNUNET_STRINGS_relative_time_to_string(ticket_refresh_interval,
1588 ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1590 // Connect to identity and namestore services
1591 nsh = GNUNET_NAMESTORE_connect(c);
1594 GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR,
1595 "error connecting to namestore");
1596 return GNUNET_SYSERR;
1598 gns = GNUNET_GNS_connect(c);
1601 GNUNET_log_strerror(GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1602 return GNUNET_SYSERR;
1604 stats = GNUNET_STATISTICS_create("reclaim", c);
1610 * Close handles and clean up.
1611 * FIXME: cancel all pending operations (gns, ns etc)
1614 RECLAIM_TICKETS_deinit(void)
1617 GNUNET_NAMESTORE_disconnect(nsh);
1620 GNUNET_GNS_disconnect(gns);
1624 GNUNET_STATISTICS_destroy(stats, GNUNET_NO);