aboutsummaryrefslogtreecommitdiff
path: root/src/reclaim/gnunet-service-reclaim_tickets.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/reclaim/gnunet-service-reclaim_tickets.c')
-rw-r--r--src/reclaim/gnunet-service-reclaim_tickets.c1853
1 files changed, 0 insertions, 1853 deletions
diff --git a/src/reclaim/gnunet-service-reclaim_tickets.c b/src/reclaim/gnunet-service-reclaim_tickets.c
deleted file mode 100644
index 5d3119c6f..000000000
--- a/src/reclaim/gnunet-service-reclaim_tickets.c
+++ /dev/null
@@ -1,1853 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2015 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @author Martin Schanzenbach
23 * @file src/reclaim/gnunet-service-reclaim_tickets.c
24 * @brief reclaim tickets
25 *
26 */
27#include <inttypes.h>
28#include "gnunet-service-reclaim_tickets.h"
29
30
31/**
32 * FIXME: the default ticket iteration interval should probably
33 * be the minimim attribute expiration.
34 */
35#define DEFAULT_TICKET_REFRESH_INTERVAL GNUNET_TIME_UNIT_HOURS
36
37/**
38 * Handle for a parallel GNS lookup job
39 * (Declaration further below)
40 */
41struct ParallelLookup;
42
43
44/**
45 * A reference to a ticket stored in GNS
46 */
47struct TicketReference
48{
49 /**
50 * DLL
51 */
52 struct TicketReference *next;
53
54 /**
55 * DLL
56 */
57 struct TicketReference *prev;
58
59 /**
60 * Attributes
61 */
62 struct GNUNET_RECLAIM_AttributeList *attrs;
63
64 /**
65 * Tickets
66 */
67 struct GNUNET_RECLAIM_Ticket ticket;
68};
69
70
71/**
72 * Handle to a consume operation
73 */
74struct RECLAIM_TICKETS_ConsumeHandle
75{
76 /**
77 * Ticket
78 */
79 struct GNUNET_RECLAIM_Ticket ticket;
80
81 /**
82 * LookupRequest
83 */
84 struct GNUNET_GNS_LookupRequest *lookup_request;
85
86 /**
87 * Audience Key
88 */
89 struct GNUNET_IDENTITY_PrivateKey identity;
90
91 /**
92 * Audience Key
93 */
94 struct GNUNET_IDENTITY_PublicKey identity_pub;
95
96 /**
97 * Lookup DLL
98 */
99 struct ParallelLookup *parallel_lookups_head;
100
101 /**
102 * Lookup DLL
103 */
104 struct ParallelLookup *parallel_lookups_tail;
105
106 /**
107 * Kill task
108 */
109 struct GNUNET_SCHEDULER_Task *kill_task;
110
111 /**
112 * Attributes
113 */
114 struct GNUNET_RECLAIM_AttributeList *attrs;
115
116 /**
117 * Presentations
118 */
119 struct GNUNET_RECLAIM_PresentationList *presentations;
120
121 /**
122 * Lookup time
123 */
124 struct GNUNET_TIME_Absolute lookup_start_time;
125
126 /**
127 * Callback
128 */
129 RECLAIM_TICKETS_ConsumeCallback cb;
130
131 /**
132 * Callback closure
133 */
134 void *cb_cls;
135};
136
137
138/**
139 * Handle for a parallel GNS lookup job
140 */
141struct ParallelLookup
142{
143 /* DLL */
144 struct ParallelLookup *next;
145
146 /* DLL */
147 struct ParallelLookup *prev;
148
149 /* The GNS request */
150 struct GNUNET_GNS_LookupRequest *lookup_request;
151
152 /* The handle the return to */
153 struct RECLAIM_TICKETS_ConsumeHandle *handle;
154
155 /**
156 * Lookup time
157 */
158 struct GNUNET_TIME_Absolute lookup_start_time;
159
160 /* The label to look up */
161 char *label;
162};
163
164
165/**
166 * Ticket issue request handle
167 */
168struct TicketIssueHandle
169{
170 /**
171 * Attributes to issue
172 */
173 struct GNUNET_RECLAIM_AttributeList *attrs;
174
175 /**
176 * Presentations to add
177 */
178 struct GNUNET_RECLAIM_PresentationList *presentations;
179
180 /**
181 * Issuer Key
182 */
183 struct GNUNET_IDENTITY_PrivateKey identity;
184
185 /**
186 * Ticket to issue
187 */
188 struct GNUNET_RECLAIM_Ticket ticket;
189
190 /**
191 * QueueEntry
192 */
193 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
194
195 /**
196 * Namestore Iterator
197 */
198 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
199
200 /**
201 * Callback
202 */
203 RECLAIM_TICKETS_TicketResult cb;
204
205 /**
206 * Callback cls
207 */
208 void *cb_cls;
209};
210
211
212/**
213 * Ticket iterator
214 */
215struct RECLAIM_TICKETS_Iterator
216{
217 /**
218 * Namestore queue entry
219 */
220 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
221
222 /**
223 * Iter callback
224 */
225 RECLAIM_TICKETS_TicketIter cb;
226
227 /**
228 * Iter cls
229 */
230 void *cb_cls;
231};
232
233
234struct RevokedAttributeEntry
235{
236 /**
237 * DLL
238 */
239 struct RevokedAttributeEntry *next;
240
241 /**
242 * DLL
243 */
244 struct RevokedAttributeEntry *prev;
245
246 /**
247 * Old ID of the attribute
248 */
249 struct GNUNET_RECLAIM_Identifier old_id;
250
251 /**
252 * New ID of the attribute
253 */
254 struct GNUNET_RECLAIM_Identifier new_id;
255};
256
257
258/**
259 * Ticket revocation request handle
260 */
261struct RECLAIM_TICKETS_RevokeHandle
262{
263 /**
264 * Issuer Key
265 */
266 struct GNUNET_IDENTITY_PrivateKey identity;
267
268 /**
269 * Callback
270 */
271 RECLAIM_TICKETS_RevokeCallback cb;
272
273 /**
274 * Callback cls
275 */
276 void *cb_cls;
277
278 /**
279 * Ticket to issue
280 */
281 struct GNUNET_RECLAIM_Ticket ticket;
282
283 /**
284 * QueueEntry
285 */
286 struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
287
288 /**
289 * Namestore iterator
290 */
291 struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
292
293 /**
294 * Revoked attributes
295 */
296 struct RevokedAttributeEntry *attrs_head;
297
298 /**
299 * Revoked attributes
300 */
301 struct RevokedAttributeEntry *attrs_tail;
302
303 /**
304 * Current attribute to move
305 */
306 struct RevokedAttributeEntry *move_attr;
307
308 /**
309 * Number of attributes in ticket
310 */
311 unsigned int ticket_attrs;
312
313 /**
314 * Tickets to update
315 */
316 struct TicketRecordsEntry *tickets_to_update_head;
317
318 /**
319 * Tickets to update
320 */
321 struct TicketRecordsEntry *tickets_to_update_tail;
322};
323
324
325/**
326 * Ticket expiration interval
327 */
328static struct GNUNET_TIME_Relative ticket_refresh_interval;
329
330
331/* Namestore handle */
332static struct GNUNET_NAMESTORE_Handle *nsh;
333
334
335/* GNS handle */
336static struct GNUNET_GNS_Handle *gns;
337
338
339/* Handle to the statistics service */
340static struct GNUNET_STATISTICS_Handle *stats;
341
342
343/**
344 * Cleanup revoke handle
345 *
346 * @param rh the ticket revocation handle
347 */
348static void
349cleanup_rvk (struct RECLAIM_TICKETS_RevokeHandle *rh)
350{
351 struct RevokedAttributeEntry *ae;
352 struct TicketRecordsEntry *le;
353
354 if (NULL != rh->ns_qe)
355 GNUNET_NAMESTORE_cancel (rh->ns_qe);
356 if (NULL != rh->ns_it)
357 GNUNET_NAMESTORE_zone_iteration_stop (rh->ns_it);
358 while (NULL != (ae = rh->attrs_head))
359 {
360 GNUNET_CONTAINER_DLL_remove (rh->attrs_head, rh->attrs_tail, ae);
361 GNUNET_free (ae);
362 }
363 while (NULL != (le = rh->tickets_to_update_head))
364 {
365 GNUNET_CONTAINER_DLL_remove (rh->tickets_to_update_head,
366 rh->tickets_to_update_head,
367 le);
368 if (NULL != le->data)
369 GNUNET_free (le->data);
370 if (NULL != le->label)
371 GNUNET_free (le->label);
372 GNUNET_free (le);
373 }
374 GNUNET_free (rh);
375}
376
377
378/**
379 * For each ticket, store new, updated attribute references
380 * (Implementation further below)
381 *
382 * @param cls handle to the operation
383 */
384static void
385process_tickets (void *cls);
386
387
388/**
389 * Finished storing updated attribute references.
390 * Abort on error, else continue processing tickets
391 *
392 * @param cls handle to the operation
393 * @param success result of namestore operation
394 * @param emsg (NULL on success)
395 */
396static void
397ticket_processed (void *cls, int32_t success, const char *emsg)
398{
399 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
400
401 rvk->ns_qe = NULL;
402 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
403}
404
405
406/**
407 * For each ticket, store new, updated attribute references
408 *
409 * @param cls handle to the operation
410 */
411static void
412process_tickets (void *cls)
413{
414 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
415 struct TicketRecordsEntry *le;
416 struct RevokedAttributeEntry *ae;
417
418 if (NULL == rvk->tickets_to_update_head)
419 {
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "Finished updatding tickets, success\n");
422 rvk->cb (rvk->cb_cls, GNUNET_OK);
423 cleanup_rvk (rvk);
424 return;
425 }
426 le = rvk->tickets_to_update_head;
427 GNUNET_CONTAINER_DLL_remove (rvk->tickets_to_update_head,
428 rvk->tickets_to_update_tail,
429 le);
430 struct GNUNET_GNSRECORD_Data rd[le->rd_count];
431 if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
432 le->data,
433 le->rd_count,
434 rd))
435 {
436 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
437 "Unable to deserialize ticket record(s)\n");
438 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
439 cleanup_rvk (rvk);
440 return;
441 }
442 for (int i = 0; i < le->rd_count; i++)
443 {
444 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
445 continue;
446 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
447 {
448 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(ae->old_id)))
449 continue;
450 rd[i].data = &ae->new_id;
451 }
452 }
453 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
454 &rvk->identity,
455 le->label,
456 le->rd_count,
457 rd,
458 &ticket_processed,
459 rvk);
460 GNUNET_free (le->label);
461 GNUNET_free (le->data);
462 GNUNET_free (le);
463}
464
465
466/**
467 * Done collecting tickets. Start processing.
468 *
469 * @param cls handle to the operation
470 */
471static void
472rvk_ticket_update_finished (void *cls)
473{
474 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
475
476 rvk->ns_it = NULL;
477 GNUNET_SCHEDULER_add_now (&process_tickets, rvk);
478}
479
480
481/**
482 * We need to update all other tickets with the new attribute IDs.
483 * We first collect them all. Processing after.
484 *
485 * @param cls handle to the operation
486 * @param zone ticket issuer private key
487 * @param label ticket rnd
488 * @param rd_cound size of record set
489 * @param rd record set
490 */
491static void
492rvk_ticket_update (void *cls,
493 const struct GNUNET_IDENTITY_PrivateKey *zone,
494 const char *label,
495 unsigned int rd_count,
496 const struct GNUNET_GNSRECORD_Data *rd)
497{
498 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
499 struct TicketRecordsEntry *le;
500 struct RevokedAttributeEntry *ae;
501 int has_changed = GNUNET_NO;
502
503 /** Let everything point to the old record **/
504 for (int i = 0; i < rd_count; i++)
505 {
506 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
507 continue;
508 for (ae = rvk->attrs_head; NULL != ae; ae = ae->next)
509 {
510 if (0 != memcmp (rd[i].data, &ae->old_id, sizeof(ae->old_id)))
511 continue;
512 has_changed = GNUNET_YES;
513 break;
514 }
515 if (GNUNET_YES == has_changed)
516 break;
517 }
518 if (GNUNET_YES == has_changed)
519 {
520 le = GNUNET_new (struct TicketRecordsEntry);
521 le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
522 le->data = GNUNET_malloc (le->data_size);
523 le->rd_count = rd_count;
524 le->label = GNUNET_strdup (label);
525 GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
526 GNUNET_CONTAINER_DLL_insert (rvk->tickets_to_update_head,
527 rvk->tickets_to_update_tail,
528 le);
529 }
530 GNUNET_NAMESTORE_zone_iterator_next (rvk->ns_it, 1);
531}
532
533
534/**
535 * Error iterating namestore. Abort.
536 *
537 * @param cls handle to the operation
538 */
539static void
540rvk_ns_iter_err (void *cls)
541{
542 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
543
544 rvk->ns_it = NULL;
545 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
546 cleanup_rvk (rvk);
547}
548
549
550/**
551 * Error storing new attribute in namestore. Abort
552 *
553 * @param cls handle to the operation
554 */
555static void
556rvk_ns_err (void *cls)
557{
558 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
559
560 rvk->ns_qe = NULL;
561 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
562 cleanup_rvk (rvk);
563}
564
565
566/**
567 * We change every attribute ID of the ticket attributes we
568 * want to revoke.
569 * When we are done, we need to update any other ticket which
570 * included references to any of the changed attributes.
571 * (Implementation further below)
572 *
573 * @param rvk handle to the operation
574 */
575static void
576move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rh);
577
578
579/**
580 * Delayed continuation for move_attrs
581 *
582 * @param cls handle to the operation.
583 */
584static void
585move_attrs_cont (void *cls)
586{
587 move_attrs ((struct RECLAIM_TICKETS_RevokeHandle *) cls);
588}
589
590
591/**
592 * Done deleting the old record. Abort on error.
593 * Else, continue updating attribute IDs.
594 *
595 * @param cls handle to the operation
596 * @param success result of the namestore operation
597 * @param emsg error message (NULL on success)
598 */
599static void
600del_attr_finished (void *cls, int32_t success, const char *emsg)
601{
602 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
603
604 rvk->ns_qe = NULL;
605 if (GNUNET_SYSERR == success)
606 {
607 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
608 "Error removing attribute: %s\n",
609 emsg);
610 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
611 cleanup_rvk (rvk);
612 return;
613 }
614 rvk->move_attr = rvk->move_attr->next;
615 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
616}
617
618
619/**
620 * Updated an attribute ID.
621 * Abort on error if namestore operation failed.
622 * Else, we have to delete the old record.
623 *
624 * @param cls handle to the operation
625 * @param success result of the store operation
626 * @param emsg error message (NULL on success)
627 */
628static void
629move_attr_finished (void *cls, int32_t success, const char *emsg)
630{
631 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
632 char *label;
633
634 rvk->ns_qe = NULL;
635 if (GNUNET_SYSERR == success)
636 {
637 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error moving attribute: %s\n", emsg);
638 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
639 cleanup_rvk (rvk);
640 return;
641 }
642 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
643 sizeof(rvk->move_attr->old_id));
644 GNUNET_assert (NULL != label);
645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removing attribute %s\n", label);
646 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
647 &rvk->identity,
648 label,
649 0,
650 NULL,
651 &del_attr_finished,
652 rvk);
653 GNUNET_free (label);
654}
655
656
657/**
658 * Got the referenced attribute. Updating the ID
659 *
660 * @param cls handle to the operation
661 * @param zone issuer identity
662 * @param label attribute ID
663 * @param rd_count size of record set (should be 1)
664 * @param rd record set (the attribute)
665 */
666static void
667rvk_move_attr_cb (void *cls,
668 const struct GNUNET_IDENTITY_PrivateKey *zone,
669 const char *label,
670 unsigned int rd_count,
671 const struct GNUNET_GNSRECORD_Data *rd)
672{
673 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
674 struct GNUNET_GNSRECORD_Data new_rd[rd_count];
675 struct RevokedAttributeEntry *le;
676 char *new_label;
677 char *attr_data;
678
679 rvk->ns_qe = NULL;
680 if (0 == rd_count)
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
683 "The claim %s no longer exists!\n",
684 label);
685 le = rvk->move_attr;
686 rvk->move_attr = le->next;
687 GNUNET_CONTAINER_DLL_remove (rvk->attrs_head, rvk->attrs_tail, le);
688 GNUNET_free (le);
689 GNUNET_SCHEDULER_add_now (&move_attrs_cont, rvk);
690 return;
691 }
692 GNUNET_RECLAIM_id_generate (&rvk->move_attr->new_id);
693 new_label =
694 GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->new_id,
695 sizeof (rvk->move_attr->new_id));
696
697 attr_data = NULL;
698 // new_rd = *rd;
699 for (int i = 0; i < rd_count; i++)
700 {
701 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE == rd[i].record_type)
702 {
703 /** find a new place for this attribute **/
704 struct GNUNET_RECLAIM_Attribute *claim;
705 GNUNET_RECLAIM_attribute_deserialize (rd[i].data,
706 rd[i].data_size,
707 &claim);
708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
709 "Attribute to update: Name=%s\n",
710 claim->name);
711 claim->id = rvk->move_attr->new_id;
712 new_rd[i].data_size = GNUNET_RECLAIM_attribute_serialize_get_size (claim);
713 attr_data = GNUNET_malloc (rd[i].data_size);
714 new_rd[i].data_size = GNUNET_RECLAIM_attribute_serialize (claim,
715 attr_data);
716 new_rd[i].data = attr_data;
717 new_rd[i].record_type = rd[i].record_type;
718 new_rd[i].flags = rd[i].flags;
719 new_rd[i].expiration_time = rd[i].expiration_time;
720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding attribute %s\n", new_label);
721 GNUNET_free (claim);
722 }
723 else if (GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL == rd[i].record_type)
724 {
725 struct GNUNET_RECLAIM_Credential *credential;
726 credential = GNUNET_RECLAIM_credential_deserialize (rd[i].data,
727 rd[i].data_size);
728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
729 "Credential to update: Name=%s\n",
730 credential->name);
731 credential->id = rvk->move_attr->new_id;
732 new_rd[i].data_size =
733 GNUNET_RECLAIM_credential_serialize_get_size (credential);
734 attr_data = GNUNET_malloc (rd[i].data_size);
735 new_rd[i].data_size = GNUNET_RECLAIM_credential_serialize (credential,
736 attr_data);
737 new_rd[i].data = attr_data;
738 new_rd[i].record_type = rd[i].record_type;
739 new_rd[i].flags = rd[i].flags;
740 new_rd[i].expiration_time = rd[i].expiration_time;
741 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Adding credential %s\n",
742 new_label);
743 GNUNET_free (credential);
744 }
745 }
746 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
747 &rvk->identity,
748 new_label,
749 rd_count,
750 new_rd,
751 &move_attr_finished,
752 rvk);
753 GNUNET_free (new_label);
754 GNUNET_free (attr_data);
755}
756
757
758/**
759 * We change every attribute ID of the ticket attributes we
760 * want to revoke.
761 * When we are done, we need to update any other ticket which
762 * included references to any of the changed attributes.
763 *
764 * @param rvk handle to the operation
765 */
766static void
767move_attrs (struct RECLAIM_TICKETS_RevokeHandle *rvk)
768{
769 char *label;
770
771 if (NULL == rvk->move_attr)
772 {
773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Finished moving attributes\n");
774 rvk->ns_it =
775 GNUNET_NAMESTORE_zone_iteration_start (nsh,
776 &rvk->identity,
777 &rvk_ns_iter_err,
778 rvk,
779 &rvk_ticket_update,
780 rvk,
781 &rvk_ticket_update_finished,
782 rvk);
783 return;
784 }
785 label = GNUNET_STRINGS_data_to_string_alloc (&rvk->move_attr->old_id,
786 sizeof (rvk->move_attr->old_id));
787 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Moving claim %s\n", label);
788
789 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
790 &rvk->identity,
791 label,
792 &rvk_ns_err,
793 rvk,
794 &rvk_move_attr_cb,
795 rvk);
796 GNUNET_free (label);
797}
798
799
800/**
801 * Finished deleting ticket and attribute references.
802 * Abort on failure.
803 * Else, we start changing every attribute ID in the
804 * found attribute references so that access is no longer
805 * possible.
806 *
807 * @param cls handle to the operation
808 * @param success Namestore operation return value
809 * @param emsg error message (NULL on success)
810 */
811static void
812remove_ticket_cont (void *cls, int32_t success, const char *emsg)
813{
814 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
815
816 rvk->ns_qe = NULL;
817 if (GNUNET_SYSERR == success)
818 {
819 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
820 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
821 cleanup_rvk (rvk);
822 return;
823 }
824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleted ticket\n");
825 if (0 == rvk->ticket_attrs)
826 {
827 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
828 "No attributes to move... strange\n");
829 rvk->cb (rvk->cb_cls, GNUNET_OK);
830 cleanup_rvk (rvk);
831 return;
832 }
833 rvk->move_attr = rvk->attrs_head;
834 move_attrs (rvk);
835}
836
837
838/**
839 * We found the attribute references.
840 * Store them for later and remove the record set.
841 *
842 * @param cls handle to the operation
843 * @param zone the issuer key
844 * @param label ticket rnd
845 * @param rd_cound size of record set
846 * @param rd record set
847 */
848static void
849revoke_attrs_cb (void *cls,
850 const struct GNUNET_IDENTITY_PrivateKey *zone,
851 const char *label,
852 unsigned int rd_count,
853 const struct GNUNET_GNSRECORD_Data *rd)
854
855{
856 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
857 struct RevokedAttributeEntry *le;
858
859 rvk->ns_qe = NULL;
860 /**
861 * Temporarily store attribute references.
862 * We need it later.
863 */
864 for (int i = 0; i < rd_count; i++)
865 {
866 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
867 continue;
868 le = GNUNET_new (struct RevokedAttributeEntry);
869 le->old_id = *((struct GNUNET_RECLAIM_Identifier *) rd[i].data);
870 GNUNET_CONTAINER_DLL_insert (rvk->attrs_head, rvk->attrs_tail, le);
871 rvk->ticket_attrs++;
872 }
873
874 /** Remove attribute references **/
875 rvk->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
876 &rvk->identity,
877 label,
878 0,
879 NULL,
880 &remove_ticket_cont,
881 rvk);
882}
883
884
885/**
886 * Failed to query namestore. Abort operation
887 *
888 * @param cls handle to the operation
889 */
890static void
891rvk_attrs_err_cb (void *cls)
892{
893 struct RECLAIM_TICKETS_RevokeHandle *rvk = cls;
894
895 rvk->cb (rvk->cb_cls, GNUNET_SYSERR);
896 cleanup_rvk (rvk);
897}
898
899
900/**
901 * Revoke a ticket.
902 * We start by looking up attribute references in order
903 * to change attribute IDs.
904 *
905 * @param ticket ticket to revoke
906 * @param identity private key of issuer
907 * @param cb revocation status callback
908 * @param cb_cls callback closure
909 * @return handle to the operation
910 */
911struct RECLAIM_TICKETS_RevokeHandle *
912RECLAIM_TICKETS_revoke (const struct GNUNET_RECLAIM_Ticket *ticket,
913 const struct GNUNET_IDENTITY_PrivateKey *identity,
914 RECLAIM_TICKETS_RevokeCallback cb,
915 void *cb_cls)
916{
917 struct RECLAIM_TICKETS_RevokeHandle *rvk;
918 char *label;
919
920 rvk = GNUNET_new (struct RECLAIM_TICKETS_RevokeHandle);
921 rvk->cb = cb;
922 rvk->cb_cls = cb_cls;
923 rvk->identity = *identity;
924 rvk->ticket = *ticket;
925 GNUNET_IDENTITY_key_get_public (&rvk->identity, &rvk->ticket.identity);
926 /** Get shared attributes **/
927 label = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd,
928 sizeof(ticket->rnd));
929 GNUNET_assert (NULL != label);
930 rvk->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
931 identity,
932 label,
933 &rvk_attrs_err_cb,
934 rvk,
935 &revoke_attrs_cb,
936 rvk);
937 GNUNET_free (label);
938 return rvk;
939}
940
941
942/**
943 * Cancel a revocation.
944 *
945 * @param rh handle to the operation
946 */
947void
948RECLAIM_TICKETS_revoke_cancel (struct RECLAIM_TICKETS_RevokeHandle *rh)
949{
950 GNUNET_assert (NULL != rh);
951 cleanup_rvk (rh);
952}
953
954
955/*******************************
956* Ticket consume
957*******************************/
958
959/**
960 * Cleanup ticket consume handle
961 *
962 * @param cth the handle to clean up
963 */
964static void
965cleanup_cth (struct RECLAIM_TICKETS_ConsumeHandle *cth)
966{
967 struct ParallelLookup *lu;
968
969 if (NULL != cth->lookup_request)
970 GNUNET_GNS_lookup_cancel (cth->lookup_request);
971 if (NULL != cth->kill_task)
972 GNUNET_SCHEDULER_cancel (cth->kill_task);
973 while (NULL != (lu = cth->parallel_lookups_head))
974 {
975 if (NULL != lu->lookup_request)
976 GNUNET_GNS_lookup_cancel (lu->lookup_request);
977 GNUNET_free (lu->label);
978 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
979 cth->parallel_lookups_tail,
980 lu);
981 GNUNET_free (lu);
982 }
983
984 if (NULL != cth->attrs)
985 GNUNET_RECLAIM_attribute_list_destroy (cth->attrs);
986 if (NULL != cth->presentations)
987 GNUNET_RECLAIM_presentation_list_destroy (cth->presentations);
988 GNUNET_free (cth);
989}
990
991
992/**
993 * We found an attribute record.
994 *
995 * @param cls handle to the operation
996 * @param rd_cound size of record set
997 * @param rd record set
998 */
999static void
1000process_parallel_lookup_result (void *cls,
1001 uint32_t rd_count,
1002 const struct GNUNET_GNSRECORD_Data *rd)
1003{
1004 struct ParallelLookup *parallel_lookup = cls;
1005 struct RECLAIM_TICKETS_ConsumeHandle *cth = parallel_lookup->handle;
1006 struct GNUNET_RECLAIM_AttributeListEntry *attr_le;
1007
1008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1009 "Parallel lookup finished (count=%u)\n",
1010 rd_count);
1011
1012 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1013 cth->parallel_lookups_tail,
1014 parallel_lookup);
1015 GNUNET_free (parallel_lookup->label);
1016
1017 GNUNET_STATISTICS_update (stats,
1018 "attribute_lookup_time_total",
1019 GNUNET_TIME_absolute_get_duration (
1020 parallel_lookup->lookup_start_time)
1021 .rel_value_us,
1022 GNUNET_YES);
1023 GNUNET_STATISTICS_update (stats, "attribute_lookups_count", 1, GNUNET_YES);
1024
1025
1026 GNUNET_free (parallel_lookup);
1027 if (0 == rd_count)
1028 GNUNET_break (0);
1029 // REMARK: It is possible now to find rd_count > 1
1030 for (int i = 0; i < rd_count; i++)
1031 {
1032 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE != rd[i].record_type)
1033 continue;
1034 attr_le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
1035 GNUNET_RECLAIM_attribute_deserialize (rd[i].data, rd[i].data_size,
1036 &attr_le->attribute);
1037 GNUNET_CONTAINER_DLL_insert (cth->attrs->list_head,
1038 cth->attrs->list_tail,
1039 attr_le);
1040 }
1041 if (NULL != cth->parallel_lookups_head)
1042 return; // Wait for more
1043 /* Else we are done */
1044 cth->cb (cth->cb_cls, &cth->ticket.identity,
1045 cth->attrs, cth->presentations, GNUNET_OK, NULL);
1046 cleanup_cth (cth);
1047}
1048
1049
1050/**
1051 * Cancel the lookups for attribute records
1052 *
1053 * @param cls handle to the operation
1054 */
1055static void
1056abort_parallel_lookups (void *cls)
1057{
1058 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1059 struct ParallelLookup *lu;
1060 struct ParallelLookup *tmp;
1061
1062 cth->kill_task = NULL;
1063 for (lu = cth->parallel_lookups_head; NULL != lu;)
1064 {
1065 GNUNET_GNS_lookup_cancel (lu->lookup_request);
1066 GNUNET_free (lu->label);
1067 tmp = lu->next;
1068 GNUNET_CONTAINER_DLL_remove (cth->parallel_lookups_head,
1069 cth->parallel_lookups_tail,
1070 lu);
1071 GNUNET_free (lu);
1072 lu = tmp;
1073 }
1074 cth->cb (cth->cb_cls, NULL, NULL, NULL, GNUNET_SYSERR, "Aborted");
1075}
1076
1077
1078/**
1079 * GNS result with attribute references.
1080 * For each result, we start a (parallel) lookup of the actual
1081 * attribute record under the referenced label.
1082 *
1083 * @param cls handle to the operation
1084 * @param rd_cound size of the record set
1085 * @param rd record set
1086 */
1087static void
1088lookup_authz_cb (void *cls,
1089 uint32_t rd_count,
1090 const struct GNUNET_GNSRECORD_Data *rd)
1091{
1092 struct RECLAIM_TICKETS_ConsumeHandle *cth = cls;
1093 struct ParallelLookup *parallel_lookup;
1094 char *lbl;
1095 struct GNUNET_RECLAIM_PresentationListEntry *ale;
1096
1097 cth->lookup_request = NULL;
1098
1099 GNUNET_STATISTICS_update (stats,
1100 "reclaim_authz_lookup_time_total",
1101 GNUNET_TIME_absolute_get_duration (
1102 cth->lookup_start_time)
1103 .rel_value_us,
1104 GNUNET_YES);
1105 GNUNET_STATISTICS_update (stats,
1106 "reclaim_authz_lookups_count",
1107 1,
1108 GNUNET_YES);
1109
1110 for (int i = 0; i < rd_count; i++)
1111 {
1112 /**
1113 * Check if record is a credential presentation or an attribute
1114 * reference.
1115 */
1116 switch (rd[i].record_type)
1117 {
1118 case GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION:
1119 ale = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
1120 ale->presentation =
1121 GNUNET_RECLAIM_presentation_deserialize (rd[i].data,
1122 rd[i].data_size);
1123 GNUNET_CONTAINER_DLL_insert (cth->presentations->list_head,
1124 cth->presentations->list_tail,
1125 ale);
1126 break;
1127 case GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF:
1128 lbl = GNUNET_STRINGS_data_to_string_alloc (rd[i].data, rd[i].data_size);
1129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ticket reference found %s\n", lbl);
1130 parallel_lookup = GNUNET_new (struct ParallelLookup);
1131 parallel_lookup->handle = cth;
1132 parallel_lookup->label = lbl;
1133 parallel_lookup->lookup_start_time = GNUNET_TIME_absolute_get ();
1134 parallel_lookup->lookup_request =
1135 GNUNET_GNS_lookup (gns,
1136 lbl,
1137 &cth->ticket.identity,
1138 GNUNET_GNSRECORD_TYPE_ANY,
1139 GNUNET_GNS_LO_DEFAULT,
1140 &process_parallel_lookup_result,
1141 parallel_lookup);
1142 GNUNET_CONTAINER_DLL_insert (cth->parallel_lookups_head,
1143 cth->parallel_lookups_tail,
1144 parallel_lookup);
1145 break;
1146 default:
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 "Ignoring unknown record type %d", rd[i].record_type);
1149 }
1150 }
1151 /**
1152 * We started lookups. Add a timeout task.
1153 * FIXME: Really needed here?
1154 */
1155 if (NULL != cth->parallel_lookups_head)
1156 {
1157 cth->kill_task = GNUNET_SCHEDULER_add_delayed (
1158 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 3),
1159 &abort_parallel_lookups,
1160 cth);
1161 return;
1162 }
1163 /**
1164 * No references found, return empty attribute list
1165 */
1166 cth->cb (cth->cb_cls, &cth->ticket.identity,
1167 cth->attrs, NULL, GNUNET_OK, NULL);
1168 cleanup_cth (cth);
1169}
1170
1171
1172/**
1173 * Consume a ticket.
1174 * We first looking attribute references under the label
1175 * ticket.rnd in GNS.
1176 *
1177 * @param id the audience of the ticket
1178 * @param ticket the ticket to consume
1179 * @param cb callback to call with attributes of ticket
1180 * @param cb_cls callback closure
1181 * @return handle to the operation
1182 */
1183struct RECLAIM_TICKETS_ConsumeHandle *
1184RECLAIM_TICKETS_consume (const struct GNUNET_IDENTITY_PrivateKey *id,
1185 const struct GNUNET_RECLAIM_Ticket *ticket,
1186 RECLAIM_TICKETS_ConsumeCallback cb,
1187 void *cb_cls)
1188{
1189 struct RECLAIM_TICKETS_ConsumeHandle *cth;
1190 char *label;
1191
1192 cth = GNUNET_new (struct RECLAIM_TICKETS_ConsumeHandle);
1193
1194 cth->identity = *id;
1195 GNUNET_IDENTITY_key_get_public (&cth->identity, &cth->identity_pub);
1196 cth->attrs = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
1197 cth->presentations = GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
1198 cth->ticket = *ticket;
1199 cth->cb = cb;
1200 cth->cb_cls = cb_cls;
1201 label =
1202 GNUNET_STRINGS_data_to_string_alloc (&cth->ticket.rnd,
1203 sizeof(cth->ticket.rnd));
1204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1205 "Looking for AuthZ info under %s\n",
1206 label);
1207 cth->lookup_start_time = GNUNET_TIME_absolute_get ();
1208 cth->lookup_request =
1209 GNUNET_GNS_lookup (gns,
1210 label,
1211 &cth->ticket.identity,
1212 GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF,
1213 GNUNET_GNS_LO_DEFAULT,
1214 &lookup_authz_cb,
1215 cth);
1216 GNUNET_free (label);
1217 return cth;
1218}
1219
1220
1221/**
1222 * Cancel a consume operation
1223 *
1224 * @param cth the operation to cancel
1225 */
1226void
1227RECLAIM_TICKETS_consume_cancel (struct RECLAIM_TICKETS_ConsumeHandle *cth)
1228{
1229 cleanup_cth (cth);
1230 return;
1231}
1232
1233
1234/*******************************
1235 * Ticket issue
1236 *******************************/
1237
1238/**
1239 * Cleanup ticket consume handle
1240 * @param handle the handle to clean up
1241 */
1242static void
1243cleanup_issue_handle (struct TicketIssueHandle *handle)
1244{
1245 if (NULL != handle->ns_qe)
1246 GNUNET_NAMESTORE_cancel (handle->ns_qe);
1247 GNUNET_free (handle);
1248}
1249
1250
1251/**
1252 * Store finished, abort on error.
1253 * Else, return new ticket to caller.
1254 *
1255 * @param cls handle to the operation
1256 * @param success store operation result
1257 * @param emsg error message (or NULL on success)
1258 */
1259static void
1260store_ticket_issue_cont (void *cls, int32_t success, const char *emsg)
1261{
1262 struct TicketIssueHandle *handle = cls;
1263
1264 handle->ns_qe = NULL;
1265 if (GNUNET_SYSERR == success)
1266 {
1267 handle->cb (handle->cb_cls,
1268 &handle->ticket,
1269 NULL,
1270 GNUNET_SYSERR,
1271 "Error storing AuthZ ticket in GNS");
1272 return;
1273 }
1274 handle->cb (handle->cb_cls,
1275 &handle->ticket,
1276 handle->presentations,
1277 GNUNET_OK, NULL);
1278 cleanup_issue_handle (handle);
1279}
1280
1281
1282/**
1283 * Issue a new ticket.
1284 * We store references to attribute record labels and the ticket itself
1285 * under the label base64(ticket.rnd).
1286 *
1287 * @param ih handle to the operation containing relevant metadata
1288 */
1289static void
1290issue_ticket (struct TicketIssueHandle *ih)
1291{
1292 struct GNUNET_RECLAIM_AttributeListEntry *le;
1293 struct GNUNET_RECLAIM_PresentationListEntry *ple;
1294 struct GNUNET_GNSRECORD_Data *attrs_record;
1295 char *label;
1296 int i;
1297 int j;
1298 int attrs_count = 0;
1299
1300 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1301 attrs_count++;
1302
1303 // Worst case we have one presentation per attribute
1304 attrs_record =
1305 GNUNET_malloc (2 * attrs_count * sizeof(struct GNUNET_GNSRECORD_Data));
1306 i = 0;
1307 for (le = ih->attrs->list_head; NULL != le; le = le->next)
1308 {
1309 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1310 "Adding list entry: %s\n", le->attribute->name);
1311
1312 attrs_record[i].data = &le->attribute->id;
1313 attrs_record[i].data_size = sizeof(le->attribute->id);
1314 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1315 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF;
1316 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1317 i++;
1318 if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential))
1319 {
1320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1321 "Attribute is backed by credential. Adding...\n");
1322 struct GNUNET_RECLAIM_Presentation *presentation = NULL;
1323 for (j = 0; j < i; j++)
1324 {
1325 if (attrs_record[j].record_type
1326 != GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION)
1327 continue;
1328 presentation = GNUNET_RECLAIM_presentation_deserialize (
1329 attrs_record[j].data,
1330 attrs_record[j].
1331 data_size);
1332 if (NULL == presentation)
1333 {
1334 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1335 "Failed to deserialize presentation\n");
1336 continue;
1337 }
1338 if (0 == memcmp (&presentation->credential_id,
1339 &le->attribute->credential,
1340 sizeof (le->attribute->credential)))
1341 break;
1342 GNUNET_free (presentation);
1343 presentation = NULL;
1344 }
1345 if (NULL != presentation)
1346 {
1347 GNUNET_free (presentation);
1348 continue; // Skip as we have already added this credential presentation.
1349 }
1350 for (ple = ih->presentations->list_head; NULL != ple; ple = ple->next)
1351 {
1352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1353 "Checking presentation....\n");
1354
1355 if (0 != memcmp (&le->attribute->credential,
1356 &ple->presentation->credential_id,
1357 sizeof (le->attribute->credential)))
1358 {
1359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1360 "Presentation does not match credential ID.\n");
1361 continue;
1362 }
1363 char *pres_buf;
1364 size_t pres_size;
1365
1366 pres_size =
1367 GNUNET_RECLAIM_presentation_serialize_get_size (ple->presentation);
1368 pres_buf = GNUNET_malloc (pres_size);
1369 GNUNET_RECLAIM_presentation_serialize (ple->presentation,
1370 pres_buf);
1371 attrs_record[i].data = pres_buf;
1372 attrs_record[i].data_size = pres_size;
1373 attrs_record[i].expiration_time =
1374 ticket_refresh_interval.rel_value_us;
1375 attrs_record[i].record_type =
1376 GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION;
1377 attrs_record[i].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1378 i++;
1379 break;
1380 }
1381 }
1382 }
1383 attrs_record[i].data = &ih->ticket;
1384 attrs_record[i].data_size = sizeof(struct GNUNET_RECLAIM_Ticket);
1385 attrs_record[i].expiration_time = ticket_refresh_interval.rel_value_us;
1386 attrs_record[i].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET;
1387 attrs_record[i].flags =
1388 GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION | GNUNET_GNSRECORD_RF_PRIVATE;
1389 i++;
1390
1391 label =
1392 GNUNET_STRINGS_data_to_string_alloc (&ih->ticket.rnd,
1393 sizeof(ih->ticket.rnd));
1394 // Publish record
1395 ih->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1396 &ih->identity,
1397 label,
1398 i,
1399 attrs_record,
1400 &store_ticket_issue_cont,
1401 ih);
1402 for (j = 0; j < i; j++)
1403 {
1404 if (attrs_record[j].record_type
1405 != GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION)
1406 continue;
1407 // Yes, we are allowed to do this because we allocated it above
1408 char *ptr = (char*) attrs_record[j].data;
1409 GNUNET_free (ptr);
1410 }
1411 GNUNET_free (attrs_record);
1412 GNUNET_free (label);
1413}
1414
1415
1416/*************************************************
1417 * Ticket iteration (finding a specific ticket)
1418 *************************************************/
1419
1420
1421/**
1422 * Namestore error on issue. Abort.
1423 *
1424 * @param cls handle to the operation
1425 */
1426static void
1427filter_tickets_error_cb (void *cls)
1428{
1429 struct TicketIssueHandle *tih = cls;
1430
1431 tih->ns_it = NULL;
1432 tih->cb (tih->cb_cls,
1433 &tih->ticket,
1434 NULL,
1435 GNUNET_SYSERR,
1436 "Error storing AuthZ ticket in GNS");
1437 cleanup_issue_handle (tih);
1438}
1439
1440
1441/**
1442 * Iterator over records.
1443 * Check if any previously issued ticket already
1444 * matches what we need to prevent duplicates and
1445 * improve resolution synergy.
1446 *
1447 * @param cls handle to the operation
1448 * @param zone issuer identity
1449 * @param label ticket rnd
1450 * @param rd_count size of record set
1451 * @param rd record set
1452 */
1453static void
1454filter_tickets_cb (void *cls,
1455 const struct GNUNET_IDENTITY_PrivateKey *zone,
1456 const char *label,
1457 unsigned int rd_count,
1458 const struct GNUNET_GNSRECORD_Data *rd)
1459{
1460 struct TicketIssueHandle *tih = cls;
1461 struct GNUNET_RECLAIM_Ticket *ticket = NULL;
1462 struct GNUNET_RECLAIM_Presentation *presentation;
1463 struct GNUNET_RECLAIM_PresentationList *ticket_presentations;
1464 struct GNUNET_RECLAIM_Credential *cred;
1465 struct GNUNET_RECLAIM_PresentationListEntry *ple;
1466 struct GNUNET_RECLAIM_AttributeListEntry *le;
1467 unsigned int attr_cnt = 0;
1468 unsigned int pres_cnt = 0;
1469
1470 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1471 {
1472 attr_cnt++;
1473 if (GNUNET_NO == GNUNET_RECLAIM_id_is_zero (&le->attribute->credential))
1474 pres_cnt++;
1475 }
1476
1477 // ticket search
1478 unsigned int found_attrs_cnt = 0;
1479 unsigned int found_pres_cnt = 0;
1480 ticket_presentations = GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
1481
1482 for (int i = 0; i < rd_count; i++)
1483 {
1484 // found ticket
1485 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET == rd[i].record_type)
1486 {
1487 ticket = (struct GNUNET_RECLAIM_Ticket *) rd[i].data;
1488 // cmp audience
1489 if (0 == memcmp (&tih->ticket.audience,
1490 &ticket->audience,
1491 sizeof(struct GNUNET_IDENTITY_PublicKey)))
1492 {
1493 tih->ticket = *ticket;
1494 continue;
1495 }
1496 ticket = NULL;
1497 }
1498
1499 // cmp requested attributes with ticket attributes
1500 if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF == rd[i].record_type)
1501 {
1502 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1503 {
1504 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1505 &le->attribute->id))
1506 found_attrs_cnt++;
1507 }
1508 }
1509 if (GNUNET_GNSRECORD_TYPE_RECLAIM_CREDENTIAL == rd[i].record_type)
1510 {
1511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1512 "Found credential...\n");
1513
1514 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1515 {
1516 cred = GNUNET_RECLAIM_credential_deserialize (rd[i].data,
1517 rd[i].data_size);
1518 if (GNUNET_YES != GNUNET_RECLAIM_id_is_equal (&cred->id,
1519 &le->attribute->credential))
1520 {
1521 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1522 "No match.\n");
1523 GNUNET_free (cred);
1524 continue;
1525 }
1526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1527 "Match, creating presentation...\n");
1528 if (GNUNET_OK != GNUNET_RECLAIM_credential_get_presentation (
1529 cred,
1530 tih->attrs,
1531 &presentation))
1532 {
1533 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1534 "Unable to retrieve presentation from credential\n");
1535 GNUNET_free (cred);
1536 continue;
1537 }
1538 ple = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
1539 ple->presentation = presentation;
1540 GNUNET_CONTAINER_DLL_insert (tih->presentations->list_head,
1541 tih->presentations->list_tail,
1542 ple);
1543 GNUNET_free (cred);
1544 break;
1545 }
1546 }
1547 if (GNUNET_GNSRECORD_TYPE_RECLAIM_PRESENTATION == rd[i].record_type)
1548 {
1549 for (le = tih->attrs->list_head; NULL != le; le = le->next)
1550 {
1551 presentation = GNUNET_RECLAIM_presentation_deserialize (rd[i].data,
1552 rd[i].data_size);
1553 if (NULL == presentation)
1554 {
1555 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1556 "Failed to deserialize presentation\n");
1557 continue;
1558 }
1559 if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (
1560 &presentation->credential_id,
1561 &le->attribute->credential))
1562 {
1563 found_pres_cnt++;
1564 ple = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry);
1565 ple->presentation = presentation;
1566 GNUNET_CONTAINER_DLL_insert (ticket_presentations->list_head,
1567 ticket_presentations->list_tail,
1568 ple);
1569 }
1570 }
1571 }
1572 }
1573
1574 /**
1575 * If we found a matching ticket, return that to the caller and
1576 * we are done.
1577 */
1578 if ((attr_cnt == found_attrs_cnt) &&
1579 (pres_cnt == found_pres_cnt) &&
1580 (NULL != ticket))
1581 {
1582 GNUNET_NAMESTORE_zone_iteration_stop (tih->ns_it);
1583 tih->cb (tih->cb_cls, &tih->ticket, ticket_presentations, GNUNET_OK, NULL);
1584 GNUNET_RECLAIM_presentation_list_destroy (ticket_presentations);
1585 cleanup_issue_handle (tih);
1586 return;
1587 }
1588 GNUNET_RECLAIM_presentation_list_destroy (ticket_presentations);
1589 // ticket not found in current record, checking next record set
1590 GNUNET_NAMESTORE_zone_iterator_next (tih->ns_it, 1);
1591}
1592
1593
1594/**
1595 * Done iterating over tickets and we apparently did
1596 * not find an existing, matching ticket.
1597 * Continue by issuing a new ticket.
1598 *
1599 * @param cls handle to the operation
1600 */
1601static void
1602filter_tickets_finished_cb (void *cls)
1603{
1604 struct TicketIssueHandle *tih = cls;
1605
1606 GNUNET_IDENTITY_key_get_public (&tih->identity, &tih->ticket.identity);
1607 GNUNET_RECLAIM_id_generate (&tih->ticket.rnd);
1608 issue_ticket (tih);
1609}
1610
1611
1612/**
1613 * Issue a new reclaim ticket, thereby authorizing
1614 * the audience to access the set of provided attributes.
1615 *
1616 * @param identity the issuer
1617 * @param attrs the attributes to share
1618 * @param audience the audience to share the attributes with
1619 * @param cb the callback to call with the ticket result
1620 * @param cb_cls the callback closure
1621 * FIXME: Return handle??
1622 */
1623void
1624RECLAIM_TICKETS_issue (const struct GNUNET_IDENTITY_PrivateKey *identity,
1625 const struct GNUNET_RECLAIM_AttributeList *attrs,
1626 const struct GNUNET_IDENTITY_PublicKey *audience,
1627 RECLAIM_TICKETS_TicketResult cb,
1628 void *cb_cls)
1629{
1630 struct TicketIssueHandle *tih;
1631
1632 tih = GNUNET_new (struct TicketIssueHandle);
1633 tih->cb = cb;
1634 tih->cb_cls = cb_cls;
1635 tih->attrs = GNUNET_RECLAIM_attribute_list_dup (attrs);
1636 tih->presentations = GNUNET_new (struct GNUNET_RECLAIM_PresentationList);
1637 tih->identity = *identity;
1638 tih->ticket.audience = *audience;
1639
1640 // First check whether the ticket has already been issued
1641 tih->ns_it =
1642 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1643 &tih->identity,
1644 &filter_tickets_error_cb,
1645 tih,
1646 &filter_tickets_cb,
1647 tih,
1648 &filter_tickets_finished_cb,
1649 tih);
1650}
1651
1652
1653/************************************
1654 * Ticket iteration
1655 ************************************/
1656
1657/**
1658 * Cleanup ticket iterator
1659 *
1660 * @param iter handle to the iteration
1661 */
1662static void
1663cleanup_iter (struct RECLAIM_TICKETS_Iterator *iter)
1664{
1665 if (NULL != iter->ns_it)
1666 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1667 GNUNET_free (iter);
1668}
1669
1670
1671/**
1672 * Return each record of type @GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET
1673 * to the caller and proceed with the iteration.
1674 * FIXME: Should we _not_ proceed automatically here?
1675 *
1676 * @param cls handle to the iteration
1677 * @param zone the ticket issuer
1678 * @param label the ticket rnd
1679 * @param rd_count number of records in record set
1680 * @param rd record set containing a ticket
1681 */
1682static void
1683collect_tickets_cb (void *cls,
1684 const struct GNUNET_IDENTITY_PrivateKey *zone,
1685 const char *label,
1686 unsigned int rd_count,
1687 const struct GNUNET_GNSRECORD_Data *rd)
1688{
1689 struct RECLAIM_TICKETS_Iterator *iter = cls;
1690
1691 for (int i = 0; i < rd_count; i++)
1692 {
1693 if (GNUNET_GNSRECORD_TYPE_RECLAIM_TICKET != rd[i].record_type)
1694 continue;
1695 iter->cb (iter->cb_cls, (struct GNUNET_RECLAIM_Ticket *) rd[i].data);
1696 return;
1697 }
1698 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1699}
1700
1701
1702/**
1703 * Signal ticket iteration has finished
1704 *
1705 * @param cls handle to the iteration
1706 */
1707static void
1708collect_tickets_finished_cb (void *cls)
1709{
1710 struct RECLAIM_TICKETS_Iterator *iter = cls;
1711
1712 iter->ns_it = NULL;
1713 iter->cb (iter->cb_cls, NULL);
1714 cleanup_iter (iter);
1715}
1716
1717
1718/**
1719 * Cancel ticket iteration on namestore error
1720 *
1721 * @param cls the iteration handle
1722 */
1723static void
1724collect_tickets_error_cb (void *cls)
1725{
1726 struct RECLAIM_TICKETS_Iterator *iter = cls;
1727
1728 iter->ns_it = NULL;
1729 iter->cb (iter->cb_cls, NULL);
1730 cleanup_iter (iter);
1731}
1732
1733
1734/**
1735 * Continue ticket iteration
1736 *
1737 * @param iter the iteration to continue
1738 */
1739void
1740RECLAIM_TICKETS_iteration_next (struct RECLAIM_TICKETS_Iterator *iter)
1741{
1742 GNUNET_NAMESTORE_zone_iterator_next (iter->ns_it, 1);
1743}
1744
1745
1746/**
1747 * Stop a running ticket iteration
1748 *
1749 * @param iter iteration to cancel
1750 */
1751void
1752RECLAIM_TICKETS_iteration_stop (struct RECLAIM_TICKETS_Iterator *iter)
1753{
1754 GNUNET_NAMESTORE_zone_iteration_stop (iter->ns_it);
1755 cleanup_iter (iter);
1756}
1757
1758
1759/**
1760 * Iterate over all tickets issued by an identity
1761 *
1762 * @param identity the issuing identity
1763 * @param cb ticket callback function
1764 * @param cb_cls callback closure
1765 * @return a handle to the iteration
1766 */
1767struct RECLAIM_TICKETS_Iterator *
1768RECLAIM_TICKETS_iteration_start (
1769 const struct GNUNET_IDENTITY_PrivateKey *identity,
1770 RECLAIM_TICKETS_TicketIter cb,
1771 void *cb_cls)
1772{
1773 struct RECLAIM_TICKETS_Iterator *iter;
1774
1775 iter = GNUNET_new (struct RECLAIM_TICKETS_Iterator);
1776 iter->cb = cb;
1777 iter->cb_cls = cb_cls;
1778 iter->ns_it =
1779 GNUNET_NAMESTORE_zone_iteration_start (nsh,
1780 identity,
1781 &collect_tickets_error_cb,
1782 iter,
1783 &collect_tickets_cb,
1784 iter,
1785 &collect_tickets_finished_cb,
1786 iter);
1787 return iter;
1788}
1789
1790
1791/**
1792 * Initialize tickets component
1793 *
1794 * @param c the configuration
1795 * @return GNUNET_SYSERR on error
1796 */
1797int
1798RECLAIM_TICKETS_init (const struct GNUNET_CONFIGURATION_Handle *c)
1799{
1800 // Get ticket expiration time (relative) from config
1801 if (GNUNET_OK ==
1802 GNUNET_CONFIGURATION_get_value_time (c,
1803 "reclaim",
1804 "TICKET_REFRESH_INTERVAL",
1805 &ticket_refresh_interval))
1806 {
1807 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1808 "Configured refresh interval for tickets: %s\n",
1809 GNUNET_STRINGS_relative_time_to_string (ticket_refresh_interval,
1810 GNUNET_YES));
1811 }
1812 else
1813 {
1814 ticket_refresh_interval = DEFAULT_TICKET_REFRESH_INTERVAL;
1815 }
1816 // Connect to identity and namestore services
1817 nsh = GNUNET_NAMESTORE_connect (c);
1818 if (NULL == nsh)
1819 {
1820 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1821 "error connecting to namestore");
1822 return GNUNET_SYSERR;
1823 }
1824 gns = GNUNET_GNS_connect (c);
1825 if (NULL == gns)
1826 {
1827 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "error connecting to gns");
1828 return GNUNET_SYSERR;
1829 }
1830 stats = GNUNET_STATISTICS_create ("reclaim", c);
1831 return GNUNET_OK;
1832}
1833
1834
1835/**
1836 * Close handles and clean up.
1837 * FIXME: cancel all pending operations (gns, ns etc)
1838 */
1839void
1840RECLAIM_TICKETS_deinit (void)
1841{
1842 if (NULL != nsh)
1843 GNUNET_NAMESTORE_disconnect (nsh);
1844 nsh = NULL;
1845 if (NULL != gns)
1846 GNUNET_GNS_disconnect (gns);
1847 gns = NULL;
1848 if (NULL != stats)
1849 {
1850 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
1851 stats = NULL;
1852 }
1853}