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;
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;
391 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
396 * For each ticket, store new, updated attribute references
398 * @param cls handle to the operation
401 process_tickets (void *cls)
403 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
404 struct TicketRecordsEntry *le;
405 struct RevokedAttributeEntry *ae;
406 if (NULL == rvk->tickets_to_update_head)
408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
409 "Finished updatding tickets, success\n");
410 rvk->cb (rvk->cb_cls, GNUNET_OK);
414 le = rvk->tickets_to_update_head;
415 GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
416 rvk->tickets_to_update_tail,
418 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
419 if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
424 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
425 "Unable to deserialize ticket record(s)\n");
426 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
430 for (int i = 0; i < le->rd_count; i++)
432 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
434 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
436 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
438 rd[i].data = &ae->new_id;
441 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
448 GNUNET_free (le->label);
449 GNUNET_free (le->data);
455 * Done collecting tickets. Start processing.
457 * @param cls handle to the operation
460 rvk_ticket_update_finished (void *cls)
462 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
464 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
469 * We need to update all other tickets with the new attribute IDs.
470 * We first collect them all. Processing after.
472 * @param cls handle to the operation
473 * @param zone ticket issuer private key
474 * @param label ticket rnd
475 * @param rd_cound size of record set
476 * @param rd record set
479 rvk_ticket_update (void *cls,
480 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
482 unsigned int rd_count,
483 const struct GNUNET_GNSRECORD_Data *rd)
485 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
486 struct TicketRecordsEntry *le;
487 struct RevokedAttributeEntry *ae;
488 int has_changed = GNUNET_NO;
490 /** Let everything point to the old record **/
491 for (int i = 0; i < rd_count; i++)
493 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
495 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
497 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof (uint64_t)))
499 has_changed = GNUNET_YES;
502 if (GNUNET_YES == has_changed)
505 if (GNUNET_YES == has_changed)
507 le = GNUNET_new (struct TicketRecordsEntry);
508 le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
509 le->data = GNUNET_malloc (le->data_size);
510 le->rd_count = rd_count;
511 le->label = GNUNET_strdup (label);
512 GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
513 GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
514 rvk->tickets_to_update_tail,
517 GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
522 * Error iterating namestore. Abort.
524 * @param cls handle to the operation
527 rvk_ns_iter_err (void *cls)
529 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
531 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
532 "Namestore error on revocation (id=%" PRIu64 "\n",
533 rvk->move_attr->old_id);
534 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
540 * Error storing new attribute in namestore. Abort
542 * @param cls handle to the operation
545 rvk_ns_err (void *cls)
547 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550 "Namestore error on revocation (id=%" PRIu64 "\n",
551 rvk->move_attr->old_id);
552 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
558 * We change every attribute ID of the ticket attributes we
560 * When we are done, we need to update any other ticket which
561 * included references to any of the changed attributes.
562 * (Implementation further below)
564 * @param rvk handle to the operation
567 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
571 * Delayed continuation for move_attrs
573 * @param cls handle to the operation.
576 move_attrs_cont (void *cls)
578 move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
583 * Done deleting the old record. Abort on error.
584 * Else, continue updating attribute IDs.
586 * @param cls handle to the operation
587 * @param success result of the namestore operation
588 * @param emsg error message (NULL on success)
591 del_attr_finished (void *cls, int32_t success, const char *emsg)
593 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;
624 if (GNUNET_SYSERR == success)
626 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
627 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
631 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
633 GNUNET_assert (NULL != label);
634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
635 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
647 * Got the referenced attribute. Updating the ID
649 * @param cls handle to the operation
650 * @param zone issuer identity
651 * @param label attribute ID
652 * @param rd_count size of record set (should be 1)
653 * @param rd record set (the attribute)
656 rvk_move_attr_cb (void *cls,
657 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
659 unsigned int rd_count,
660 const struct GNUNET_GNSRECORD_Data *rd)
662 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
663 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
664 struct GNUNET_GNSRECORD_Data new_rd;
665 struct RevokedAttributeEntry *le;
671 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
672 "The attribute %s no longer exists!\n",
675 rvk->move_attr = le->next;
676 GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
678 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
681 /** find a new place for this attribute **/
682 rvk->move_attr->new_id =
683 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
685 claim = GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
687 "Attribute to update: Name=%s, ID=%" PRIu64 "\n",
690 claim->id = rvk->move_attr->new_id;
691 new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize_get_size (claim);
692 attr_data = GNUNET_malloc (rd->data_size);
693 new_rd.data_size = GNUNET_RECLAIM_ATTRIBUTE_serialize (claim, attr_data);
694 new_rd.data = attr_data;
695 new_label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
698 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
705 GNUNET_free (new_label);
707 GNUNET_free (attr_data);
712 * We change every attribute ID of the ticket attributes we
714 * When we are done, we need to update any other ticket which
715 * included references to any of the changed attributes.
717 * @param rvk handle to the operation
720 move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
724 if (NULL == rvk->move_attr)
726 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
728 GNUNET_NAMESTORE_zone_iteration_start (nsh,
734 &rvk_ticket_update_finished,
738 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving attribute %s\n", label);
742 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
754 * Finished deleting ticket and attribute references.
756 * Else, we start changing every attribute ID in the
757 * found attribute references so that access is no longer
760 * @param cls handle to the operation
761 * @param success Namestore operation return value
762 * @param emsg error message (NULL on success)
765 remove_ticket_cont (void *cls, int32_t success, const char *emsg)
767 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
769 if (GNUNET_SYSERR == success)
771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
772 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
777 if (0 == rvk->ticket_attrs)
779 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
780 "No attributes to move... strange\n");
781 rvk->cb (rvk->cb_cls, GNUNET_OK);
785 rvk->move_attr = rvk->attrs_head;
791 * We found the attribute references.
792 * Store them for later and remove the record set.
794 * @param cls handle to the operation
795 * @param zone the issuer key
796 * @param label ticket rnd
797 * @param rd_cound size of record set
798 * @param rd record set
801 revoke_attrs_cb (void *cls,
802 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
804 unsigned int rd_count,
805 const struct GNUNET_GNSRECORD_Data *rd)
808 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
809 struct RevokedAttributeEntry *le;
812 * Temporarily store attribute references.
815 for (int i = 0; i < rd_count; i++)
817 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
819 le = GNUNET_new (struct RevokedAttributeEntry);
820 le->old_id = *((uint64_t *) rd[i].data);
821 GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
825 /** Remove attribute references **/
826 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
837 * Failed to query namestore. Abort operation
839 * @param cls handle to the operation
842 rvk_attrs_err_cb (void *cls)
844 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
845 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
852 * We start by looking up attribute references in order
853 * to change attribute IDs.
855 * @param ticket ticket to revoke
856 * @param identity private key of issuer
857 * @param cb revocation status callback
858 * @param cb_cls callback closure
859 * @return handle to the operation
861 struct RECLAIM_TICKETS_RevokeHandle *
862 RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
863 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
864 RECLAIM_TICKETS_RevokeCallback cb,
867 struct RECLAIM_TICKETS_RevokeHandle *rvk;
870 rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
872 rvk->cb_cls = cb_cls;
873 rvk->identity = *identity;
874 rvk->ticket = *ticket;
875 GNUNET_CRYPTO_ecdsa_key_get_public (&rvk->identity, &rvk->ticket.identity);
876 /** Get shared attributes **/
877 label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
878 GNUNET_assert (NULL != label);
879 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
892 * Cancel a revocation.
894 * @param rh handle to the operation
897 RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
899 GNUNET_assert (NULL != rh);
904 /*******************************
906 *******************************/
909 * Cleanup ticket consume handle
911 * @param cth the handle to clean up
914 cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
916 struct ParallelLookup *lu;
917 if (NULL != cth->lookup_request)
918 GNUNET_GNS_lookup_cancel (cth->lookup_request);
919 if (NULL != cth->kill_task)
920 GNUNET_SCHEDULER_cancel (cth->kill_task);
921 while (NULL != (lu = cth->parallel_lookups_head))
923 if (NULL != lu->lookup_request)
924 GNUNET_GNS_lookup_cancel (lu->lookup_request);
925 GNUNET_free_non_null (lu->label);
926 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
927 cth->parallel_lookups_tail,
932 if (NULL != cth->attrs)
933 GNUNET_RECLAIM_ATTRIBUTE_list_destroy (cth->attrs);
939 * We found an attribute record.
941 * @param cls handle to the operation
942 * @param rd_cound size of record set
943 * @param rd record set
946 process_parallel_lookup_result (void *cls,
948 const struct GNUNET_GNSRECORD_Data *rd)
950 struct ParallelLookup *parallel_lookup = cls;
951 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
952 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *attr_le;
953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954 "Parallel lookup finished (count=%u)\n",
957 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
958 cth->parallel_lookups_tail,
960 GNUNET_free (parallel_lookup->label);
962 GNUNET_STATISTICS_update (stats,
963 "attribute_lookup_time_total",
964 GNUNET_TIME_absolute_get_duration (
965 parallel_lookup->lookup_start_time)
968 GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
971 GNUNET_free (parallel_lookup);
973 GNUNET_break (0); // FIXME: We should never find this.
974 if (rd->record_type == GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR)
976 attr_le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
978 GNUNET_RECLAIM_ATTRIBUTE_deserialize (rd->data, rd->data_size);
979 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
980 cth->attrs->list_tail,
984 if (NULL != cth->parallel_lookups_head)
985 return; // Wait for more
987 /* Else we are done */
988 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
994 * Cancel the lookups for attribute records
996 * @param cls handle to the operation
999 abort_parallel_lookups (void *cls)
1001 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1002 struct ParallelLookup *lu;
1003 struct ParallelLookup *tmp;
1005 cth->kill_task = NULL;
1006 for (lu = cth->parallel_lookups_head; NULL != lu;)
1008 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1009 GNUNET_free (lu->label);
1011 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1012 cth->parallel_lookups_tail,
1017 cth->cb (cth->cb_cls, NULL, NULL, GNUNET_SYSERR, "Aborted");
1022 * GNS result with attribute references.
1023 * For each result, we start a (parallel) lookup of the actual
1024 * attribute record under the referenced label.
1026 * @param cls handle to the operation
1027 * @param rd_cound size of the record set
1028 * @param rd record set
1031 lookup_authz_cb (void *cls,
1033 const struct GNUNET_GNSRECORD_Data *rd)
1035 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1036 struct ParallelLookup *parallel_lookup;
1039 cth->lookup_request = NULL;
1041 GNUNET_STATISTICS_update (stats,
1042 "reclaim_authz_lookup_time_total",
1043 GNUNET_TIME_absolute_get_duration (
1044 cth->lookup_start_time)
1047 GNUNET_STATISTICS_update (stats,
1048 "reclaim_authz_lookups_count",
1052 for (int i = 0; i < rd_count; i++)
1054 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1056 lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
1057 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Attribute ref found %s\n", lbl);
1058 parallel_lookup = GNUNET_new (struct ParallelLookup);
1059 parallel_lookup->handle = cth;
1060 parallel_lookup->label = lbl;
1061 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
1062 parallel_lookup->lookup_request =
1063 GNUNET_GNS_lookup (gns,
1065 &cth->ticket.identity,
1066 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR,
1067 GNUNET_GNS_LO_DEFAULT,
1068 &process_parallel_lookup_result,
1070 GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
1071 cth->parallel_lookups_tail,
1075 * We started lookups. Add a timeout task.
1076 * FIXME: Really needed here?
1078 if (NULL != cth->parallel_lookups_head)
1080 cth->kill_task = GNUNET_SCHEDULER_add_delayed (
1081 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
1082 &abort_parallel_lookups,
1087 * No references found, return empty attribute list
1089 cth->cb (cth->cb_cls, &cth->ticket.identity, cth->attrs, GNUNET_OK, NULL);
1096 * We first looking attribute references under the label
1097 * ticket.rnd in GNS.
1099 * @param id the audience of the ticket
1100 * @param ticket the ticket to consume
1101 * @param cb callback to call with attributes of ticket
1102 * @param cb_cls callback closure
1103 * @return handle to the operation
1105 struct RECLAIM_TICKETS_ConsumeHandle *
1106 RECLAIM_TICKETS_consume (const struct GNUNET_CRYPTO_EcdsaPrivateKey *id,
1107 const struct GNUNET_RECLAIM_Ticket *ticket,
1108 RECLAIM_TICKETS_ConsumeCallback cb,
1111 struct RECLAIM_TICKETS_ConsumeHandle *cth;
1113 cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
1115 cth->identity = *id;
1116 GNUNET_CRYPTO_ecdsa_key_get_public (&cth->identity, &cth->identity_pub);
1117 cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
1118 cth->ticket = *ticket;
1120 cth->cb_cls = cb_cls;
1122 GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd, sizeof (uint64_t));
1123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1124 "Looking for AuthZ info under %s\n",
1126 cth->lookup_start_time = GNUNET_TIME_absolute_get ();
1127 cth->lookup_request =
1128 GNUNET_GNS_lookup (gns,
1130 &cth->ticket.identity,
1131 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF,
1132 GNUNET_GNS_LO_DEFAULT,
1135 GNUNET_free (label);
1141 * Cancel a consume operation
1143 * @param cth the operation to cancel
1146 RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
1153 /*******************************
1155 *******************************/
1158 * Cleanup ticket consume handle
1159 * @param handle the handle to clean up
1162 cleanup_issue_handle (struct TicketIssueHandle *handle)
1164 if (NULL != handle->ns_qe)
1165 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1166 GNUNET_free (handle);
1171 * Store finished, abort on error.
1172 * Else, return new ticket to caller.
1174 * @param cls handle to the operation
1175 * @param success store operation result
1176 * @param emsg error message (or NULL on success)
1179 store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
1181 struct TicketIssueHandle *handle = cls;
1183 handle->ns_qe = NULL;
1184 if (GNUNET_SYSERR == success)
1186 handle->cb (handle->cb_cls,
1189 "Error storing AuthZ ticket in GNS");
1192 handle->cb (handle->cb_cls, &handle->ticket, GNUNET_OK, NULL);
1193 cleanup_issue_handle (handle);
1198 * Issue a new ticket.
1199 * We store references to attribute record labels and the ticket itself
1200 * under the label base64(ticket.rnd).
1202 * @param ih handle to the operation containing relevant metadata
1205 issue_ticket (struct TicketIssueHandle *ih)
1207 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1208 struct GNUNET_GNSRECORD_Data *attrs_record;
1210 size_t list_len = 1;
1213 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1217 GNUNET_malloc (list_len * sizeof (struct GNUNET_GNSRECORD_Data));
1219 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1221 attrs_record[i].data = &le->claim->id;
1222 attrs_record[i].data_size = sizeof (le->claim->id);
1224 * FIXME: Should this be the attribute expiration time or ticket
1225 * refresh interval? Probably min(attrs.expiration)
1227 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1228 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF;
1229 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1232 attrs_record[i].data = &ih->ticket;
1233 attrs_record[i].data_size = sizeof (struct GNUNET_RECLAIM_Ticket);
1234 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1235 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1236 attrs_record[i].flags =
1237 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1240 GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd, sizeof (uint64_t));
1242 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1247 &store_ticket_issue_cont,
1249 GNUNET_free (attrs_record);
1250 GNUNET_free (label);
1253 /*************************************************
1254 * Ticket iteration (finding a specific ticket)
1255 *************************************************/
1259 * Namestore error on issue. Abort.
1261 * @param cls handle to the operation
1264 filter_tickets_error_cb (void *cls)
1266 struct TicketIssueHandle *tih = cls;
1268 tih->cb (tih->cb_cls,
1271 "Error storing AuthZ ticket in GNS");
1272 cleanup_issue_handle (tih);
1277 * Iterator over records.
1278 * Check if any previously issued ticket already
1279 * matches what we need to prevent duplicates and
1280 * improve resolution synergy.
1282 * @param cls handle to the operation
1283 * @param zone issuer identity
1284 * @param label ticket rnd
1285 * @param rd_count size of record set
1286 * @param rd record set
1289 filter_tickets_cb (void *cls,
1290 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1292 unsigned int rd_count,
1293 const struct GNUNET_GNSRECORD_Data *rd)
1295 struct TicketIssueHandle *tih = cls;
1296 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1298 // figure out the number of requested attributes
1299 struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
1300 unsigned int attr_cnt = 0;
1301 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1305 unsigned int found_attrs_cnt = 0;
1307 for (int i = 0; i < rd_count; i++)
1310 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
1312 ticket = (struct GNUNET_RECLAIM_Ticket *) rd[i].data;
1314 if (0 == memcmp (&tih->ticket.audience,
1316 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
1318 tih->ticket = *ticket;
1324 // cmp requested attributes with ticket attributes
1325 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTR_REF != rd[i].record_type)
1327 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1329 // cmp attr_ref id with requested attr id
1330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1331 " %" PRIu64 "\n %" PRIu64 "\n",
1332 *((uint64_t *) rd[i].data),
1336 if (0 == memcmp (rd[i].data, &le->claim->id, sizeof (uint64_t)))
1342 * If we found a matching ticket, return that to the caller and
1345 if (attr_cnt == found_attrs_cnt && NULL != ticket)
1347 GNUNET_NAMESTORE_zone_iteration_stop (tih->ns_it);
1348 tih->cb (tih->cb_cls, &tih->ticket, GNUNET_OK, NULL);
1349 cleanup_issue_handle (tih);
1353 // ticket not found in current record, checking next record set
1354 GNUNET_NAMESTORE_zone_iterator_next (tih->ns_it, 1);
1359 * Done iterating over tickets and we apparently did
1360 * not find an existing, matching ticket.
1361 * Continue by issuing a new ticket.
1363 * @param cls handle to the operation
1366 filter_tickets_finished_cb (void *cls)
1368 struct TicketIssueHandle *tih = cls;
1369 GNUNET_CRYPTO_ecdsa_key_get_public (&tih->identity, &tih->ticket.identity);
1371 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_STRONG, UINT64_MAX);
1377 * Issue a new reclaim ticket, thereby authorizing
1378 * the audience to access the set of provided attributes.
1380 * @param identity the issuer
1381 * @param attrs the attributes to share
1382 * @param audience the audience to share the attributes with
1383 * @param cb the callback to call with the ticket result
1384 * @param cb_cls the callback closure
1385 * FIXME: Return handle??
1388 RECLAIM_TICKETS_issue (const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1389 const struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attrs,
1390 const struct GNUNET_CRYPTO_EcdsaPublicKey *audience,
1391 RECLAIM_TICKETS_TicketResult cb,
1394 struct TicketIssueHandle *tih;
1395 tih = GNUNET_new (struct TicketIssueHandle);
1397 tih->cb_cls = cb_cls;
1398 tih->attrs = GNUNET_RECLAIM_ATTRIBUTE_list_dup (attrs);
1399 tih->identity = *identity;
1400 tih->ticket.audience = *audience;
1402 // First check whether the ticket has already been issued
1404 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1406 &filter_tickets_error_cb,
1410 &filter_tickets_finished_cb,
1415 /************************************
1417 ************************************/
1420 * Cleanup ticket iterator
1422 * @param iter handle to the iteration
1425 cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
1427 if (NULL != iter->ns_it)
1428 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1434 * Return each record of type @GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET
1435 * to the caller and proceed with the iteration.
1436 * FIXME: Should we _not_ proceed automatically here?
1438 * @param cls handle to the iteration
1439 * @param zone the ticket issuer
1440 * @param label the ticket rnd
1441 * @param rd_count number of records in record set
1442 * @param rd record set containing a ticket
1445 collect_tickets_cb (void *cls,
1446 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1448 unsigned int rd_count,
1449 const struct GNUNET_GNSRECORD_Data *rd)
1451 struct RECLAIM_TICKETS_Iterator *iter = cls;
1453 for (int i = 0; i < rd_count; i++)
1455 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1457 iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *) rd[i].data);
1460 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1465 * Signal ticket iteration has finished
1467 * @param cls handle to the iteration
1470 collect_tickets_finished_cb (void *cls)
1472 struct RECLAIM_TICKETS_Iterator *iter = cls;
1474 iter->cb (iter->cb_cls, NULL);
1475 cleanup_iter (iter);
1480 * Cancel ticket iteration on namestore error
1482 * @param cls the iteration handle
1485 collect_tickets_error_cb (void *cls)
1487 struct RECLAIM_TICKETS_Iterator *iter = cls;
1489 iter->cb (iter->cb_cls, NULL);
1490 cleanup_iter (iter);
1495 * Continue ticket iteration
1497 * @param iter the iteration to continue
1500 RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
1502 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1507 * Stop a running ticket iteration
1509 * @param iter iteration to cancel
1512 RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
1514 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1515 cleanup_iter (iter);
1520 * Iterate over all tickets issued by an identity
1522 * @param identity the issuing identity
1523 * @param cb ticket callback function
1524 * @param cb_cls callback closure
1525 * @return a handle to the iteration
1527 struct RECLAIM_TICKETS_Iterator *
1528 RECLAIM_TICKETS_iteration_start (
1529 const struct GNUNET_CRYPTO_EcdsaPrivateKey *identity,
1530 RECLAIM_TICKETS_TicketIter cb,
1533 struct RECLAIM_TICKETS_Iterator *iter;
1535 iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1537 iter->cb_cls = cb_cls;
1539 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1541 &collect_tickets_error_cb,
1543 &collect_tickets_cb,
1545 &collect_tickets_finished_cb,
1552 * Initialize tickets component
1554 * @param c the configuration
1555 * @return GNUNET_SYSERR on error
1558 RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1560 // Get ticket expiration time (relative) from config
1562 GNUNET_CONFIGURATION_get_value_time (c,
1564 "TICKET_REFRESH_INTERVAL",
1565 &ticket_refresh_interval))
1567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1568 "Configured refresh interval for tickets: %s\n",
1569 GNUNET_STRINGS_relative_time_to_string (ticket_refresh_interval,
1574 ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1576 // Connect to identity and namestore services
1577 nsh = GNUNET_NAMESTORE_connect (c);
1580 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1581 "error connecting to namestore");
1582 return GNUNET_SYSERR;
1584 gns = GNUNET_GNS_connect (c);
1587 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1588 return GNUNET_SYSERR;
1590 stats = GNUNET_STATISTICS_create ("reclaim", c);
1596 * Close handles and clean up.
1597 * FIXME: cancel all pending operations (gns, ns etc)
1600 RECLAIM_TICKETS_deinit (void)
1603 GNUNET_NAMESTORE_disconnect (nsh);
1606 GNUNET_GNS_disconnect (gns);
1610 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);