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