15f9a8385946ca14b4d4a6b21163ddf998710718
[oweals/gnunet.git] / src / reclaim / gnunet-service-reclaim.c
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  * @author Martin Schanzenbach
22  * @file src/reclaim/gnunet-service-reclaim.c
23  * @brief reclaim Service
24  *
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet-service-reclaim_tickets.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_gnsrecord_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_reclaim_attribute_lib.h"
33 #include "gnunet_reclaim_service.h"
34 #include "gnunet_signatures.h"
35 #include "reclaim.h"
36
37
38 /**
39  * Namestore handle
40  */
41 static struct GNUNET_NAMESTORE_Handle *nsh;
42
43 /**
44  * Timeout task
45  */
46 static struct GNUNET_SCHEDULER_Task *timeout_task;
47
48 /**
49  * Our configuration.
50  */
51 static const struct GNUNET_CONFIGURATION_Handle *cfg;
52
53 /**
54  * An idp client
55  */
56 struct IdpClient;
57
58 /**
59  * A ticket iteration operation.
60  */
61 struct TicketIteration
62 {
63   /**
64    * DLL
65    */
66   struct TicketIteration *next;
67
68   /**
69    * DLL
70    */
71   struct TicketIteration *prev;
72
73   /**
74    * Client which intiated this zone iteration
75    */
76   struct IdpClient *client;
77
78   /**
79    * The operation id fot the iteration in the response for the client
80    */
81   uint32_t r_id;
82
83   /**
84    * The ticket iterator
85    */
86   struct RECLAIM_TICKETS_Iterator *iter;
87 };
88
89
90 /**
91  * An attribute iteration operation.
92  */
93 struct AttributeIterator
94 {
95   /**
96    * Next element in the DLL
97    */
98   struct AttributeIterator *next;
99
100   /**
101    * Previous element in the DLL
102    */
103   struct AttributeIterator *prev;
104
105   /**
106    * IDP client which intiated this zone iteration
107    */
108   struct IdpClient *client;
109
110   /**
111    * Key of the zone we are iterating over.
112    */
113   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
114
115   /**
116    * Namestore iterator
117    */
118   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
119
120   /**
121    * The operation id fot the zone iteration in the response for the client
122    */
123   uint32_t request_id;
124 };
125
126
127 /**
128  * An idp client
129  */
130 struct IdpClient
131 {
132   /**
133    * DLL
134    */
135   struct IdpClient *prev;
136
137   /**
138    * DLL
139    */
140   struct IdpClient *next;
141
142   /**
143    * The client
144    */
145   struct GNUNET_SERVICE_Client *client;
146
147   /**
148    * Message queue for transmission to @e client
149    */
150   struct GNUNET_MQ_Handle *mq;
151
152   /**
153    * Head of the DLL of
154    * Attribute iteration operations in
155    * progress initiated by this client
156    */
157   struct AttributeIterator *attr_iter_head;
158
159   /**
160    * Tail of the DLL of
161    * Attribute iteration operations
162    * in progress initiated by this client
163    */
164   struct AttributeIterator *attr_iter_tail;
165
166   /**
167    * Head of DLL of ticket iteration ops
168    */
169   struct TicketIteration *ticket_iter_head;
170
171   /**
172    * Tail of DLL of ticket iteration ops
173    */
174   struct TicketIteration *ticket_iter_tail;
175
176   /**
177    * Head of DLL of ticket revocation ops
178    */
179   struct TicketRevocationOperation *revoke_op_head;
180
181   /**
182    * Tail of DLL of ticket revocation ops
183    */
184   struct TicketRevocationOperation *revoke_op_tail;
185
186   /**
187    * Head of DLL of ticket issue ops
188    */
189   struct TicketIssueOperation *issue_op_head;
190
191   /**
192    * Tail of DLL of ticket issue ops
193    */
194   struct TicketIssueOperation *issue_op_tail;
195
196   /**
197    * Head of DLL of ticket consume ops
198    */
199   struct ConsumeTicketOperation *consume_op_head;
200
201   /**
202    * Tail of DLL of ticket consume ops
203    */
204   struct ConsumeTicketOperation *consume_op_tail;
205
206   /**
207    * Head of DLL of attribute store ops
208    */
209   struct AttributeStoreHandle *store_op_head;
210
211   /**
212    * Tail of DLL of attribute store ops
213    */
214   struct AttributeStoreHandle *store_op_tail;
215   /**
216    * Head of DLL of attribute delete ops
217    */
218   struct AttributeDeleteHandle *delete_op_head;
219
220   /**
221    * Tail of DLL of attribute delete ops
222    */
223   struct AttributeDeleteHandle *delete_op_tail;
224 };
225
226
227 /**
228  * Handle for attribute deletion request
229  */
230 struct AttributeDeleteHandle
231 {
232   /**
233    * DLL
234    */
235   struct AttributeDeleteHandle *next;
236
237   /**
238    * DLL
239    */
240   struct AttributeDeleteHandle *prev;
241
242   /**
243    * Client connection
244    */
245   struct IdpClient *client;
246
247   /**
248    * Identity
249    */
250   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
251
252
253   /**
254    * QueueEntry
255    */
256   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
257
258   /**
259    * Iterator
260    */
261   struct GNUNET_NAMESTORE_ZoneIterator *ns_it;
262
263   /**
264    * The attribute to delete
265    */
266   struct GNUNET_RECLAIM_Attribute *claim;
267
268   /**
269    * The attestation to delete
270    */
271   struct GNUNET_RECLAIM_Attestation *attest;
272
273   /**
274    * Tickets to update
275    */
276   struct TicketRecordsEntry *tickets_to_update_head;
277
278   /**
279    * Tickets to update
280    */
281   struct TicketRecordsEntry *tickets_to_update_tail;
282
283   /**
284    * Attribute label
285    */
286   char *label;
287
288   /**
289    * request id
290    */
291   uint32_t r_id;
292 };
293
294
295 /**
296  * Handle for attribute store request
297  */
298 struct AttributeStoreHandle
299 {
300   /**
301    * DLL
302    */
303   struct AttributeStoreHandle *next;
304
305   /**
306    * DLL
307    */
308   struct AttributeStoreHandle *prev;
309
310   /**
311    * Client connection
312    */
313   struct IdpClient *client;
314
315   /**
316    * Identity
317    */
318   struct GNUNET_CRYPTO_EcdsaPrivateKey identity;
319
320   /**
321    * Identity pubkey
322    */
323   struct GNUNET_CRYPTO_EcdsaPublicKey identity_pkey;
324
325   /**
326    * QueueEntry
327    */
328   struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
329
330   /**
331    * The attribute to store
332    */
333   struct GNUNET_RECLAIM_Attribute *claim;
334
335   /**
336   * The attestation to store
337   */
338   struct GNUNET_RECLAIM_Attestation *attest;
339
340   /**
341    * The attribute expiration interval
342    */
343   struct GNUNET_TIME_Relative exp;
344
345   /**
346    * request id
347    */
348   uint32_t r_id;
349 };
350
351
352 /**
353  * Handle for ticket consume request
354  */
355 struct ConsumeTicketOperation
356 {
357   /**
358    * DLL
359    */
360   struct ConsumeTicketOperation *next;
361
362   /**
363    * DLL
364    */
365   struct ConsumeTicketOperation *prev;
366
367   /**
368    * Client connection
369    */
370   struct IdpClient *client;
371
372   /**
373    * request id
374    */
375   uint32_t r_id;
376
377   /**
378    * Ticket consume handle
379    */
380   struct RECLAIM_TICKETS_ConsumeHandle *ch;
381 };
382
383
384 /**
385  * Ticket revocation request handle
386  */
387 struct TicketRevocationOperation
388 {
389   /**
390    * DLL
391    */
392   struct TicketRevocationOperation *prev;
393
394   /**
395    * DLL
396    */
397   struct TicketRevocationOperation *next;
398
399   /**
400    * Client connection
401    */
402   struct IdpClient *client;
403
404   /**
405    * Revocation handle
406    */
407   struct RECLAIM_TICKETS_RevokeHandle *rh;
408
409   /**
410    * request id
411    */
412   uint32_t r_id;
413 };
414
415
416 /**
417  * Ticket issue operation handle
418  */
419 struct TicketIssueOperation
420 {
421   /**
422    * DLL
423    */
424   struct TicketIssueOperation *prev;
425
426   /**
427    * DLL
428    */
429   struct TicketIssueOperation *next;
430
431   /**
432    * Client connection
433    */
434   struct IdpClient *client;
435
436   /**
437    * request id
438    */
439   uint32_t r_id;
440 };
441
442
443 /**
444  * Client list
445  */
446 static struct IdpClient *client_list_head = NULL;
447
448 /**
449  * Client list
450  */
451 static struct IdpClient *client_list_tail = NULL;
452
453
454 /**
455  * Cleanup attribute delete handle
456  *
457  * @param adh the attribute to cleanup
458  */
459 static void
460 cleanup_adh (struct AttributeDeleteHandle *adh)
461 {
462   struct TicketRecordsEntry *le;
463
464   if (NULL != adh->ns_it)
465     GNUNET_NAMESTORE_zone_iteration_stop (adh->ns_it);
466   if (NULL != adh->ns_qe)
467     GNUNET_NAMESTORE_cancel (adh->ns_qe);
468   if (NULL != adh->label)
469     GNUNET_free (adh->label);
470   if (NULL != adh->claim)
471     GNUNET_free (adh->claim);
472   if (NULL != adh->attest)
473     GNUNET_free (adh->attest);
474   while (NULL != (le = adh->tickets_to_update_head))
475   {
476     GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
477                                  adh->tickets_to_update_tail,
478                                  le);
479     if (NULL != le->label)
480       GNUNET_free (le->label);
481     if (NULL != le->data)
482       GNUNET_free (le->data);
483     GNUNET_free (le);
484   }
485   GNUNET_free (adh);
486 }
487
488
489 /**
490  * Cleanup attribute store handle
491  *
492  * @param handle handle to clean up
493  */
494 static void
495 cleanup_as_handle (struct AttributeStoreHandle *ash)
496 {
497   if (NULL != ash->ns_qe)
498     GNUNET_NAMESTORE_cancel (ash->ns_qe);
499   if (NULL != ash->claim)
500     GNUNET_free (ash->claim);
501   if (NULL != ash->attest)
502     GNUNET_free (ash->attest);
503   GNUNET_free (ash);
504 }
505
506
507 /**
508  * Cleanup client
509  *
510  * @param idp the client to clean up
511  */
512 static void
513 cleanup_client (struct IdpClient *idp)
514 {
515   struct AttributeIterator *ai;
516   struct TicketIteration *ti;
517   struct TicketRevocationOperation *rop;
518   struct TicketIssueOperation *iss;
519   struct ConsumeTicketOperation *ct;
520   struct AttributeStoreHandle *as;
521   struct AttributeDeleteHandle *adh;
522
523   while (NULL != (iss = idp->issue_op_head))
524   {
525     GNUNET_CONTAINER_DLL_remove (idp->issue_op_head, idp->issue_op_tail, iss);
526     GNUNET_free (iss);
527   }
528   while (NULL != (ct = idp->consume_op_head))
529   {
530     GNUNET_CONTAINER_DLL_remove (idp->consume_op_head,
531                                  idp->consume_op_tail,
532                                  ct);
533     if (NULL != ct->ch)
534       RECLAIM_TICKETS_consume_cancel (ct->ch);
535     GNUNET_free (ct);
536   }
537   while (NULL != (as = idp->store_op_head))
538   {
539     GNUNET_CONTAINER_DLL_remove (idp->store_op_head, idp->store_op_tail, as);
540     cleanup_as_handle (as);
541   }
542   while (NULL != (adh = idp->delete_op_head))
543   {
544     GNUNET_CONTAINER_DLL_remove (idp->delete_op_head, idp->delete_op_tail, adh);
545     cleanup_adh (adh);
546   }
547
548   while (NULL != (ai = idp->attr_iter_head))
549   {
550     GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
551     GNUNET_free (ai);
552   }
553   while (NULL != (rop = idp->revoke_op_head))
554   {
555     GNUNET_CONTAINER_DLL_remove (idp->revoke_op_head, idp->revoke_op_tail, rop);
556     if (NULL != rop->rh)
557       RECLAIM_TICKETS_revoke_cancel (rop->rh);
558     GNUNET_free (rop);
559   }
560   while (NULL != (ti = idp->ticket_iter_head))
561   {
562     GNUNET_CONTAINER_DLL_remove (idp->ticket_iter_head,
563                                  idp->ticket_iter_tail,
564                                  ti);
565     if (NULL != ti->iter)
566       RECLAIM_TICKETS_iteration_stop (ti->iter);
567     GNUNET_free (ti);
568   }
569   GNUNET_free (idp);
570 }
571
572
573 /**
574  * Cleanup task
575  */
576 static void
577 cleanup ()
578 {
579   struct IdpClient *cl;
580
581   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n");
582
583   while (NULL != (cl = client_list_head))
584   {
585     GNUNET_CONTAINER_DLL_remove (client_list_head,
586                                  client_list_tail,
587                                  cl);
588     cleanup_client (cl);
589   }
590   RECLAIM_TICKETS_deinit ();
591   if (NULL != timeout_task)
592     GNUNET_SCHEDULER_cancel (timeout_task);
593   if (NULL != nsh)
594     GNUNET_NAMESTORE_disconnect (nsh);
595 }
596
597
598 /**
599  * Shutdown task
600  *
601  * @param cls NULL
602  */
603 static void
604 do_shutdown (void *cls)
605 {
606   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
607   cleanup ();
608 }
609
610
611 /**
612  * Sends a ticket result message to the client
613  *
614  * @param client the client to send to
615  * @param r_id the request message ID to reply to
616  * @param ticket the ticket to include (may be NULL)
617  * @param success the success status of the request
618  */
619 static void
620 send_ticket_result (const struct IdpClient *client,
621                     uint32_t r_id,
622                     const struct GNUNET_RECLAIM_Ticket *ticket,
623                     uint32_t success)
624 {
625   struct TicketResultMessage *irm;
626   struct GNUNET_MQ_Envelope *env;
627
628   env = GNUNET_MQ_msg (irm,
629                        GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
630   if (NULL != ticket)
631   {
632     irm->ticket = *ticket;
633   }
634   // TODO add success member
635   irm->id = htonl (r_id);
636   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
637   GNUNET_MQ_send (client->mq, env);
638 }
639
640
641 /**
642  * Issue ticket result
643  *
644  * @param cls out ticket issue operation handle
645  * @param ticket the issued ticket
646  * @param success issue success status (GNUNET_OK if successful)
647  * @param emsg error message (NULL of success is GNUNET_OK)
648  */
649 static void
650 issue_ticket_result_cb (void *cls,
651                         struct GNUNET_RECLAIM_Ticket *ticket,
652                         int32_t success,
653                         const char *emsg)
654 {
655   struct TicketIssueOperation *tio = cls;
656
657   if (GNUNET_OK != success)
658   {
659     send_ticket_result (tio->client, tio->r_id, NULL, GNUNET_SYSERR);
660     GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
661                                  tio->client->issue_op_tail,
662                                  tio);
663     GNUNET_free (tio);
664     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error issuing ticket: %s\n", emsg);
665     return;
666   }
667   send_ticket_result (tio->client, tio->r_id, ticket, GNUNET_SYSERR);
668   GNUNET_CONTAINER_DLL_remove (tio->client->issue_op_head,
669                                tio->client->issue_op_tail,
670                                tio);
671   GNUNET_free (tio);
672 }
673
674
675 /**
676  * Check issue ticket message
677  *
678  * @cls unused
679  * @im message to check
680  * @return GNUNET_OK if message is ok
681  */
682 static int
683 check_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
684 {
685   uint16_t size;
686
687   size = ntohs (im->header.size);
688   if (size <= sizeof(struct IssueTicketMessage))
689   {
690     GNUNET_break (0);
691     return GNUNET_SYSERR;
692   }
693   return GNUNET_OK;
694 }
695
696
697 /**
698  * Handle ticket issue message
699  *
700  * @param cls our client
701  * @param im the message
702  */
703 static void
704 handle_issue_ticket_message (void *cls, const struct IssueTicketMessage *im)
705 {
706   struct TicketIssueOperation *tio;
707   struct IdpClient *idp = cls;
708   struct GNUNET_RECLAIM_AttributeList *attrs;
709   size_t attrs_len;
710
711   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ISSUE_TICKET message\n");
712   tio = GNUNET_new (struct TicketIssueOperation);
713   attrs_len = ntohs (im->attr_len);
714   attrs = GNUNET_RECLAIM_attribute_list_deserialize ((char *) &im[1],
715                                                      attrs_len);
716   tio->r_id = ntohl (im->id);
717   tio->client = idp;
718   GNUNET_CONTAINER_DLL_insert (idp->issue_op_head, idp->issue_op_tail, tio);
719   RECLAIM_TICKETS_issue (&im->identity,
720                          attrs,
721                          &im->rp,
722                          &issue_ticket_result_cb,
723                          tio);
724   GNUNET_SERVICE_client_continue (idp->client);
725   GNUNET_RECLAIM_attribute_list_destroy (attrs);
726 }
727
728
729 /**********************************************************
730 * Revocation
731 **********************************************************/
732
733 /**
734  * Handles revocation result
735  *
736  * @param cls our revocation operation handle
737  * @param success revocation result (GNUNET_OK if successful)
738  */
739 static void
740 revoke_result_cb (void *cls, int32_t success)
741 {
742   struct TicketRevocationOperation *rop = cls;
743   struct GNUNET_MQ_Envelope *env;
744   struct RevokeTicketResultMessage *trm;
745
746   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
747               "Sending REVOKE_TICKET_RESULT message\n");
748   rop->rh = NULL;
749   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET_RESULT);
750   trm->id = htonl (rop->r_id);
751   trm->success = htonl (success);
752   GNUNET_MQ_send (rop->client->mq, env);
753   GNUNET_CONTAINER_DLL_remove (rop->client->revoke_op_head,
754                                rop->client->revoke_op_tail,
755                                rop);
756   GNUNET_free (rop);
757 }
758
759
760 /**
761  * Check revocation message format
762  *
763  * @param cls unused
764  * @param im the message to check
765  * @return GNUNET_OK if message is ok
766  */
767 static int
768 check_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *im)
769 {
770   uint16_t size;
771
772   size = ntohs (im->header.size);
773   if (size != sizeof(struct RevokeTicketMessage))
774   {
775     GNUNET_break (0);
776     return GNUNET_SYSERR;
777   }
778   return GNUNET_OK;
779 }
780
781
782 /**
783  * Handle a revocation message to a ticket.
784  *
785  * @param cls our client
786  * @param rm the message to handle
787  */
788 static void
789 handle_revoke_ticket_message (void *cls, const struct RevokeTicketMessage *rm)
790 {
791   struct TicketRevocationOperation *rop;
792   struct IdpClient *idp = cls;
793
794   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received REVOKE_TICKET message\n");
795   rop = GNUNET_new (struct TicketRevocationOperation);
796   rop->r_id = ntohl (rm->id);
797   rop->client = idp;
798   GNUNET_CONTAINER_DLL_insert (idp->revoke_op_head, idp->revoke_op_tail, rop);
799   rop->rh
800     = RECLAIM_TICKETS_revoke (&rm->ticket, &rm->identity, &revoke_result_cb,
801                               rop);
802   GNUNET_SERVICE_client_continue (idp->client);
803 }
804
805
806 /**
807  * Handle a ticket consume result
808  *
809  * @param cls our consume ticket operation handle
810  * @param identity the attribute authority
811  * @param attrs the attribute/claim list
812  * @param success GNUNET_OK if successful
813  * @param emsg error message (NULL if success=GNUNET_OK)
814  */
815 static void
816 consume_result_cb (void *cls,
817                    const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
818                    const struct GNUNET_RECLAIM_AttributeList *attrs,
819                    int32_t success,
820                    const char *emsg)
821 {
822   struct ConsumeTicketOperation *cop = cls;
823   struct ConsumeTicketResultMessage *crm;
824   struct GNUNET_MQ_Envelope *env;
825   char *data_tmp;
826   size_t attrs_len;
827
828   if (GNUNET_OK != success)
829   {
830     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error consuming ticket: %s\n", emsg);
831   }
832   attrs_len = GNUNET_RECLAIM_attribute_list_serialize_get_size (attrs);
833   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
834               "Sending CONSUME_TICKET_RESULT message\n");
835   env = GNUNET_MQ_msg_extra (crm,
836                              attrs_len,
837                              GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET_RESULT);
838   crm->id = htonl (cop->r_id);
839   crm->attrs_len = htons (attrs_len);
840   crm->identity = *identity;
841   crm->result = htonl (success);
842   data_tmp = (char *) &crm[1];
843   GNUNET_RECLAIM_attribute_list_serialize (attrs, data_tmp);
844   GNUNET_MQ_send (cop->client->mq, env);
845   GNUNET_CONTAINER_DLL_remove (cop->client->consume_op_head,
846                                cop->client->consume_op_tail,
847                                cop);
848   GNUNET_free (cop);
849 }
850
851
852 /**
853  * Check a consume ticket message
854  *
855  * @param cls unused
856  * @param cm the message to handle
857  */
858 static int
859 check_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
860 {
861   uint16_t size;
862
863   size = ntohs (cm->header.size);
864   if (size != sizeof(struct ConsumeTicketMessage))
865   {
866     GNUNET_break (0);
867     return GNUNET_SYSERR;
868   }
869   return GNUNET_OK;
870 }
871
872
873 /**
874  * Handle a consume ticket message
875  *
876  * @param cls our client handle
877  * @cm the message to handle
878  */
879 static void
880 handle_consume_ticket_message (void *cls, const struct ConsumeTicketMessage *cm)
881 {
882   struct ConsumeTicketOperation *cop;
883   struct IdpClient *idp = cls;
884
885   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received CONSUME_TICKET message\n");
886   cop = GNUNET_new (struct ConsumeTicketOperation);
887   cop->r_id = ntohl (cm->id);
888   cop->client = idp;
889   cop->ch
890     = RECLAIM_TICKETS_consume (&cm->identity, &cm->ticket, &consume_result_cb,
891                                cop);
892   GNUNET_CONTAINER_DLL_insert (idp->consume_op_head, idp->consume_op_tail, cop);
893   GNUNET_SERVICE_client_continue (idp->client);
894 }
895
896
897 /*****************************************
898 * Attribute store
899 *****************************************/
900
901
902 /**
903  * Attribute store result handler
904  *
905  * @param cls our attribute store handle
906  * @param success GNUNET_OK if successful
907  * @param emsg error message (NULL if success=GNUNET_OK)
908  */
909 static void
910 attr_store_cont (void *cls, int32_t success, const char *emsg)
911 {
912   struct AttributeStoreHandle *ash = cls;
913   struct GNUNET_MQ_Envelope *env;
914   struct SuccessResultMessage *acr_msg;
915
916   ash->ns_qe = NULL;
917   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
918                                ash->client->store_op_tail,
919                                ash);
920
921   if (GNUNET_SYSERR == success)
922   {
923     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
924                 "Failed to store attribute %s\n",
925                 emsg);
926     cleanup_as_handle (ash);
927     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
928     return;
929   }
930
931   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
932   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
933   acr_msg->id = htonl (ash->r_id);
934   acr_msg->op_result = htonl (GNUNET_OK);
935   GNUNET_MQ_send (ash->client->mq, env);
936   cleanup_as_handle (ash);
937 }
938
939
940 /**
941  * Add a new attribute
942  *
943  * @param cls the AttributeStoreHandle
944  */
945 static void
946 attr_store_task (void *cls)
947 {
948   struct AttributeStoreHandle *ash = cls;
949   struct GNUNET_GNSRECORD_Data rd[1];
950   char *buf;
951   char *label;
952   size_t buf_size;
953
954   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Storing attribute\n");
955   buf_size = GNUNET_RECLAIM_attribute_serialize_get_size (ash->claim);
956   buf = GNUNET_malloc (buf_size);
957   // Give the ash a new id if unset
958   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&ash->claim->id))
959     GNUNET_RECLAIM_id_generate (&ash->claim->id);
960   GNUNET_RECLAIM_attribute_serialize (ash->claim, buf);
961   label
962     = GNUNET_STRINGS_data_to_string_alloc (&ash->claim->id,
963                                            sizeof (ash->claim->id));
964   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
965
966   rd[0].data_size = buf_size;
967   rd[0].data = buf;
968   rd[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE;
969   rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
970   rd[0].expiration_time = ash->exp.rel_value_us;
971   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
972                                                &ash->identity,
973                                                label,
974                                                1,
975                                                rd,
976                                                &attr_store_cont,
977                                                ash);
978   GNUNET_free (buf);
979   GNUNET_free (label);
980 }
981
982
983 /**
984  * Check an attribute store message
985  *
986  * @param cls unused
987  * @param sam the message to check
988  */
989 static int
990 check_attribute_store_message (void *cls,
991                                const struct AttributeStoreMessage *sam)
992 {
993   uint16_t size;
994
995   size = ntohs (sam->header.size);
996   if (size <= sizeof(struct AttributeStoreMessage))
997   {
998     GNUNET_break (0);
999     return GNUNET_SYSERR;
1000   }
1001   return GNUNET_OK;
1002 }
1003
1004
1005 /**
1006  * Handle an attribute store message
1007  *
1008  * @param cls our client
1009  * @param sam the message to handle
1010  */
1011 static void
1012 handle_attribute_store_message (void *cls,
1013                                 const struct AttributeStoreMessage *sam)
1014 {
1015   struct AttributeStoreHandle *ash;
1016   struct IdpClient *idp = cls;
1017   size_t data_len;
1018
1019   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_STORE message\n");
1020
1021   data_len = ntohs (sam->attr_len);
1022
1023   ash = GNUNET_new (struct AttributeStoreHandle);
1024   ash->claim = GNUNET_RECLAIM_attribute_deserialize ((char *) &sam[1],
1025                                                      data_len);
1026
1027   ash->r_id = ntohl (sam->id);
1028   ash->identity = sam->identity;
1029   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1030   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
1031
1032   GNUNET_SERVICE_client_continue (idp->client);
1033   ash->client = idp;
1034   GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
1035   GNUNET_SCHEDULER_add_now (&attr_store_task, ash);
1036 }
1037
1038
1039 /**
1040  * Attestation store result handler
1041  *
1042  * @param cls our attribute store handle
1043  * @param success GNUNET_OK if successful
1044  * @param emsg error message (NULL if success=GNUNET_OK)
1045  */
1046 static void
1047 attest_store_cont (void *cls, int32_t success, const char *emsg)
1048 {
1049   struct AttributeStoreHandle *ash = cls;
1050   struct GNUNET_MQ_Envelope *env;
1051   struct SuccessResultMessage *acr_msg;
1052
1053   ash->ns_qe = NULL;
1054   GNUNET_CONTAINER_DLL_remove (ash->client->store_op_head,
1055                                ash->client->store_op_tail,
1056                                ash);
1057
1058   if (GNUNET_SYSERR == success)
1059   {
1060     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1061                 "Failed to store attestation %s\n",
1062                 emsg);
1063     cleanup_as_handle (ash);
1064     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1065     return;
1066   }
1067
1068   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1069   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1070   acr_msg->id = htonl (ash->r_id);
1071   acr_msg->op_result = htonl (GNUNET_OK);
1072   GNUNET_MQ_send (ash->client->mq, env);
1073   cleanup_as_handle (ash);
1074 }
1075
1076
1077 /**
1078  * Error looking up potential attestation. Abort.
1079  *
1080  * @param cls our attribute store handle
1081  */
1082 static void
1083 attest_error (void *cls)
1084 {
1085   struct AttributeStoreHandle *ash = cls;
1086   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1087               "Failed to check for existing Attestation\n");
1088   cleanup_as_handle (ash);
1089   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
1090   return;
1091 }
1092
1093
1094 /**
1095 * Check for existing record before storing attestation
1096 *
1097 * @param cls our attribute store handle
1098 * @param zone zone we are iterating
1099 * @param label label of the records
1100 * @param rd_count record count
1101 * @param rd records
1102 */
1103 static void
1104 attest_add_cb (void *cls,
1105                const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1106                const char *label,
1107                unsigned int rd_count,
1108                const struct GNUNET_GNSRECORD_Data *rd)
1109 {
1110   struct AttributeStoreHandle *ash = cls;
1111   char *buf;
1112   size_t buf_size;
1113   buf_size = GNUNET_RECLAIM_attestation_serialize_get_size (ash->attest);
1114   buf = GNUNET_malloc (buf_size);
1115   GNUNET_RECLAIM_attestation_serialize (ash->attest, buf);
1116   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1117               "Storing new Attestation\n");
1118   struct GNUNET_GNSRECORD_Data rd_new[1];
1119   rd_new[0].data_size = buf_size;
1120   rd_new[0].data = buf;
1121   rd_new[0].record_type = GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION;
1122   rd_new[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1123   rd_new[0].expiration_time = ash->exp.rel_value_us;
1124   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Encrypting with label %s\n", label);
1125   ash->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1126                                                &ash->identity,
1127                                                label,
1128                                                1,
1129                                                rd_new,
1130                                                &attest_store_cont,
1131                                                ash);
1132   GNUNET_free (buf);
1133   return;
1134 }
1135
1136
1137 /**
1138  * Add a new attestation
1139  *
1140  * @param cls the AttributeStoreHandle
1141  */
1142 static void
1143 attest_store_task (void *cls)
1144 {
1145   struct AttributeStoreHandle *ash = cls;
1146   char *label;
1147
1148   // Give the ash a new id if unset
1149   if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&ash->attest->id))
1150     GNUNET_RECLAIM_id_generate (&ash->attest->id);
1151   label = GNUNET_STRINGS_data_to_string_alloc (&ash->attest->id,
1152                                                sizeof (ash->attest->id));
1153   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1154               "Looking up existing data under label %s\n", label);
1155 // Test for the content of the existing ID
1156   ash->ns_qe = GNUNET_NAMESTORE_records_lookup (nsh,
1157                                                 &ash->identity,
1158                                                 label,
1159                                                 &attest_error,
1160                                                 ash,
1161                                                 &attest_add_cb,
1162                                                 ash);
1163   GNUNET_free (label);
1164 }
1165
1166
1167 /**
1168  * Check an attestation store message
1169  *
1170  * @param cls unused
1171  * @param sam the message to check
1172  */
1173 static int
1174 check_attestation_store_message (void *cls,
1175                                  const struct AttributeStoreMessage *sam)
1176 {
1177   uint16_t size;
1178
1179   size = ntohs (sam->header.size);
1180   if (size <= sizeof(struct AttributeStoreMessage))
1181   {
1182     GNUNET_break (0);
1183     return GNUNET_SYSERR;
1184   }
1185   return GNUNET_OK;
1186 }
1187
1188
1189 /**
1190 * Handle an attestation store message
1191 *
1192 * @param cls our client
1193 * @param sam the message to handle
1194 */
1195 static void
1196 handle_attestation_store_message (void *cls,
1197                                   const struct AttributeStoreMessage *sam)
1198 {
1199   struct AttributeStoreHandle *ash;
1200   struct IdpClient *idp = cls;
1201   size_t data_len;
1202
1203   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTESTATION_STORE message\n");
1204
1205   data_len = ntohs (sam->attr_len);
1206
1207   ash = GNUNET_new (struct AttributeStoreHandle);
1208   ash->attest = GNUNET_RECLAIM_attestation_deserialize ((char *) &sam[1],
1209                                                         data_len);
1210
1211   ash->r_id = ntohl (sam->id);
1212   ash->identity = sam->identity;
1213   ash->exp.rel_value_us = GNUNET_ntohll (sam->exp);
1214   GNUNET_CRYPTO_ecdsa_key_get_public (&sam->identity, &ash->identity_pkey);
1215
1216   GNUNET_SERVICE_client_continue (idp->client);
1217   ash->client = idp;
1218   GNUNET_CONTAINER_DLL_insert (idp->store_op_head, idp->store_op_tail, ash);
1219   GNUNET_SCHEDULER_add_now (&attest_store_task, ash);
1220 }
1221
1222
1223 /**
1224  * Send a deletion success response
1225  *
1226  * @param adh our attribute deletion handle
1227  * @param success the success status
1228  */
1229 static void
1230 send_delete_response (struct AttributeDeleteHandle *adh, int32_t success)
1231 {
1232   struct GNUNET_MQ_Envelope *env;
1233   struct SuccessResultMessage *acr_msg;
1234
1235   GNUNET_CONTAINER_DLL_remove (adh->client->delete_op_head,
1236                                adh->client->delete_op_tail,
1237                                adh);
1238
1239   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending SUCCESS_RESPONSE message\n");
1240   env = GNUNET_MQ_msg (acr_msg, GNUNET_MESSAGE_TYPE_RECLAIM_SUCCESS_RESPONSE);
1241   acr_msg->id = htonl (adh->r_id);
1242   acr_msg->op_result = htonl (success);
1243   GNUNET_MQ_send (adh->client->mq, env);
1244 }
1245
1246
1247 /**
1248  * Namestore iteration within attribute deletion.
1249  * We need to reissue tickets with the deleted attribute removed.
1250  *
1251  * @param cls our attribute deletion handle
1252  * @param zone the private key of the ticket issuer
1253  * @param label the label of the record
1254  * @param rd_count number of records
1255  * @param rd record data
1256  */
1257 static void
1258 ticket_iter (void *cls,
1259              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1260              const char *label,
1261              unsigned int rd_count,
1262              const struct GNUNET_GNSRECORD_Data *rd)
1263 {
1264   struct AttributeDeleteHandle *adh = cls;
1265   struct TicketRecordsEntry *le;
1266   int has_changed = GNUNET_NO;
1267   for (int i = 0; i < rd_count; i++)
1268   {
1269     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF != rd[i].record_type)
1270       continue;
1271     if (adh->claim != NULL)
1272       if (GNUNET_YES != GNUNET_RECLAIM_id_is_equal (rd[i].data,
1273                                                     &adh->claim->id))
1274         continue;
1275     if (adh->attest != NULL)
1276       if (GNUNET_YES != GNUNET_RECLAIM_id_is_equal (rd[i].data,
1277                                                     &adh->attest->id))
1278         continue;
1279     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1280                 "Attribute or Attestation to delete found (%s)\n",
1281                 adh->label);
1282     has_changed = GNUNET_YES;
1283     break;
1284   }
1285   if (GNUNET_YES == has_changed)
1286   {
1287     le = GNUNET_new (struct TicketRecordsEntry);
1288     le->data_size = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
1289     le->data = GNUNET_malloc (le->data_size);
1290     le->rd_count = rd_count;
1291     le->label = GNUNET_strdup (label);
1292     GNUNET_GNSRECORD_records_serialize (rd_count, rd, le->data_size, le->data);
1293     GNUNET_CONTAINER_DLL_insert (adh->tickets_to_update_head,
1294                                  adh->tickets_to_update_tail,
1295                                  le);
1296   }
1297   GNUNET_NAMESTORE_zone_iterator_next (adh->ns_it, 1);
1298 }
1299
1300
1301 /**
1302  * Recursion prototype for function
1303  * @param cls our deletion handle
1304  */
1305 static void
1306 update_tickets (void *cls);
1307
1308
1309 /**
1310  * Callback called when a ticket was updated
1311  *
1312  * @param cls our attribute deletion handle
1313  * @param success GNUNET_OK if successful
1314  * @param emsg error message (NULL if success=GNUNET_OK)
1315  */
1316 static void
1317 ticket_updated (void *cls, int32_t success, const char *emsg)
1318 {
1319   struct AttributeDeleteHandle *adh = cls;
1320
1321   adh->ns_qe = NULL;
1322   GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1323 }
1324
1325
1326 /**
1327  * Update tickets: Remove shared attribute which has just been deleted.
1328  * This method is called recursively until all tickets are processed.
1329  * Eventually, the updated tickets are stored using ``update_tickets''.
1330  *
1331  * @param cls our attribute deletion handle
1332  */
1333 static void
1334 update_tickets (void *cls)
1335 {
1336   struct AttributeDeleteHandle *adh = cls;
1337   struct TicketRecordsEntry *le;
1338
1339   if (NULL == adh->tickets_to_update_head)
1340   {
1341     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1342                 "Finished updating tickets, success\n");
1343     send_delete_response (adh, GNUNET_OK);
1344     cleanup_adh (adh);
1345     return;
1346   }
1347   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1348               "Updating %s\n",
1349               adh->tickets_to_update_head->label);
1350   le = adh->tickets_to_update_head;
1351   GNUNET_CONTAINER_DLL_remove (adh->tickets_to_update_head,
1352                                adh->tickets_to_update_tail,
1353                                le);
1354   struct GNUNET_GNSRECORD_Data rd[le->rd_count];
1355   struct GNUNET_GNSRECORD_Data rd_new[le->rd_count - 1];
1356   if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (le->data_size,
1357                                                          le->data,
1358                                                          le->rd_count,
1359                                                          rd))
1360   {
1361     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1362                 "Unable to deserialize record data!\n");
1363     send_delete_response (adh, GNUNET_SYSERR);
1364     cleanup_adh (adh);
1365     return;
1366   }
1367   int j = 0;
1368   for (int i = 0; i < le->rd_count; i++)
1369   {
1370     if (adh->claim != NULL)
1371       if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF == rd[i].record_type)
1372           && (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1373                                                         &adh->claim->id)))
1374         continue;
1375     if (adh->attest != NULL)
1376       if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF == rd[i].record_type)
1377           && (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (rd[i].data,
1378                                                         &adh->attest->id)))
1379         continue;
1380     rd_new[j] = rd[i];
1381     j++;
1382   }
1383   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1384                                                &adh->identity,
1385                                                le->label,
1386                                                j,
1387                                                rd_new,
1388                                                &ticket_updated,
1389                                                adh);
1390   GNUNET_free (le->label);
1391   GNUNET_free (le->data);
1392   GNUNET_free (le);
1393 }
1394
1395
1396 /**
1397  * Done collecting affected tickets, start updating.
1398  *
1399  * @param cls our attribute deletion handle
1400  */
1401 static void
1402 ticket_iter_fin (void *cls)
1403 {
1404   struct AttributeDeleteHandle *adh = cls;
1405   adh->ns_it = NULL;
1406   GNUNET_SCHEDULER_add_now (&update_tickets, adh);
1407 }
1408
1409
1410 /**
1411  * Error collecting affected tickets. Abort.
1412  *
1413  * @param cls our attribute deletion handle
1414  */
1415 static void
1416 ticket_iter_err (void *cls)
1417 {
1418   struct AttributeDeleteHandle *adh = cls;
1419
1420   adh->ns_it = NULL;
1421   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1422               "Namestore error on delete %s\n",
1423               adh->label);
1424   send_delete_response (adh, GNUNET_SYSERR);
1425   cleanup_adh (adh);
1426 }
1427
1428
1429 /**
1430  * Start processing tickets which may still contain reference to deleted
1431  * attribute.
1432  *
1433  * @param cls attribute deletion handle
1434  */
1435 static void
1436 start_ticket_update (void *cls)
1437 {
1438   struct AttributeDeleteHandle *adh = cls;
1439
1440   adh->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1441                                                       &adh->identity,
1442                                                       &ticket_iter_err,
1443                                                       adh,
1444                                                       &ticket_iter,
1445                                                       adh,
1446                                                       &ticket_iter_fin,
1447                                                       adh);
1448 }
1449
1450
1451 /**
1452  * Attribute deleted callback
1453  *
1454  * @param cls our handle
1455  * @param success success status
1456  * @param emsg error message (NULL if success=GNUNET_OK)
1457  */
1458 static void
1459 attr_delete_cont (void *cls, int32_t success, const char *emsg)
1460 {
1461   struct AttributeDeleteHandle *adh = cls;
1462
1463   adh->ns_qe = NULL;
1464   if (GNUNET_SYSERR == success)
1465   {
1466     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1467                 "Error deleting attribute %s\n",
1468                 adh->label);
1469     send_delete_response (adh, GNUNET_SYSERR);
1470     cleanup_adh (adh);
1471     return;
1472   }
1473   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
1474   GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
1475 }
1476
1477
1478 /**
1479  * Check attribute delete message format
1480  *
1481  * @cls unused
1482  * @dam message to check
1483  */
1484 static int
1485 check_attribute_delete_message (void *cls,
1486                                 const struct AttributeDeleteMessage *dam)
1487 {
1488   uint16_t size;
1489
1490   size = ntohs (dam->header.size);
1491   if (size <= sizeof(struct AttributeDeleteMessage))
1492   {
1493     GNUNET_break (0);
1494     return GNUNET_SYSERR;
1495   }
1496   return GNUNET_OK;
1497 }
1498
1499
1500 /**
1501  * Handle attribute deletion
1502  *
1503  * @param cls our client
1504  * @param dam deletion message
1505  */
1506 static void
1507 handle_attribute_delete_message (void *cls,
1508                                  const struct AttributeDeleteMessage *dam)
1509 {
1510   struct AttributeDeleteHandle *adh;
1511   struct IdpClient *idp = cls;
1512   size_t data_len;
1513
1514   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTRIBUTE_DELETE message\n");
1515
1516   data_len = ntohs (dam->attr_len);
1517
1518   adh = GNUNET_new (struct AttributeDeleteHandle);
1519   adh->claim = GNUNET_RECLAIM_attribute_deserialize ((char *) &dam[1],
1520                                                      data_len);
1521   adh->attest = NULL;
1522
1523   adh->r_id = ntohl (dam->id);
1524   adh->identity = dam->identity;
1525   adh->label
1526     = GNUNET_STRINGS_data_to_string_alloc (&adh->claim->id,
1527                                            sizeof(adh->claim->id));
1528   GNUNET_SERVICE_client_continue (idp->client);
1529   adh->client = idp;
1530   GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1531   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1532                                                &adh->identity,
1533                                                adh->label,
1534                                                0,
1535                                                NULL,
1536                                                &attr_delete_cont,
1537                                                adh);
1538 }
1539
1540
1541 /**
1542    * Attestation deleted callback
1543    *
1544    * @param cls our handle
1545    * @param success success status
1546    * @param emsg error message (NULL if success=GNUNET_OK)
1547    */
1548 static void
1549 attest_delete_cont (void *cls, int32_t success, const char *emsg)
1550 {
1551   struct AttributeDeleteHandle *adh = cls;
1552
1553   adh->ns_qe = NULL;
1554   if (GNUNET_SYSERR == success)
1555   {
1556     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1557                 "Error deleting attestation %s\n",
1558                 adh->label);
1559     send_delete_response (adh, GNUNET_SYSERR);
1560     cleanup_adh (adh);
1561     return;
1562   }
1563   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Updating tickets...\n");
1564   GNUNET_SCHEDULER_add_now (&start_ticket_update, adh);
1565 }
1566
1567
1568 /**
1569  * Check attestation delete message format
1570  *
1571  * @cls unused
1572  * @dam message to check
1573  */
1574 static int
1575 check_attestation_delete_message (void *cls,
1576                                   const struct AttributeDeleteMessage *dam)
1577 {
1578   uint16_t size;
1579
1580   size = ntohs (dam->header.size);
1581   if (size <= sizeof(struct AttributeDeleteMessage))
1582   {
1583     GNUNET_break (0);
1584     return GNUNET_SYSERR;
1585   }
1586   return GNUNET_OK;
1587 }
1588
1589
1590 /**
1591  * Handle attestation deletion
1592  *
1593  * @param cls our client
1594  * @param dam deletion message
1595  */
1596 static void
1597 handle_attestation_delete_message (void *cls,
1598                                    const struct AttributeDeleteMessage *dam)
1599 {
1600   struct AttributeDeleteHandle *adh;
1601   struct IdpClient *idp = cls;
1602   size_t data_len;
1603
1604   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ATTESTATION_DELETE message\n");
1605
1606   data_len = ntohs (dam->attr_len);
1607
1608   adh = GNUNET_new (struct AttributeDeleteHandle);
1609   adh->attest = GNUNET_RECLAIM_attestation_deserialize ((char *) &dam[1],
1610                                                         data_len);
1611   adh->claim = NULL;
1612
1613   adh->r_id = ntohl (dam->id);
1614   adh->identity = dam->identity;
1615   adh->label
1616     = GNUNET_STRINGS_data_to_string_alloc (&adh->attest->id,
1617                                            sizeof(adh->attest->id));
1618   GNUNET_SERVICE_client_continue (idp->client);
1619   adh->client = idp;
1620   GNUNET_CONTAINER_DLL_insert (idp->delete_op_head, idp->delete_op_tail, adh);
1621   adh->ns_qe = GNUNET_NAMESTORE_records_store (nsh,
1622                                                &adh->identity,
1623                                                adh->label,
1624                                                0,
1625                                                NULL,
1626                                                &attest_delete_cont,
1627                                                adh);
1628 }
1629
1630
1631 /*************************************************
1632 * Attrubute iteration
1633 *************************************************/
1634
1635
1636 /**
1637  * Done iterating over attributes
1638  *
1639  * @param cls our iterator handle
1640  */
1641 static void
1642 attr_iter_finished (void *cls)
1643 {
1644   struct AttributeIterator *ai = cls;
1645   struct GNUNET_MQ_Envelope *env;
1646   struct AttributeResultMessage *arm;
1647
1648   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ATTRIBUTE_RESULT message\n");
1649   env = GNUNET_MQ_msg (arm, GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1650   arm->id = htonl (ai->request_id);
1651   arm->attr_len = htons (0);
1652   GNUNET_MQ_send (ai->client->mq, env);
1653   GNUNET_CONTAINER_DLL_remove (ai->client->attr_iter_head,
1654                                ai->client->attr_iter_tail,
1655                                ai);
1656   GNUNET_free (ai);
1657 }
1658
1659
1660 /**
1661  * Error iterating over attributes. Abort.
1662  *
1663  * @param cls our attribute iteration handle
1664  */
1665 static void
1666 attr_iter_error (void *cls)
1667 {
1668   struct AttributeIterator *ai = cls;
1669
1670   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to iterate over attributes\n");
1671   attr_iter_finished (ai);
1672 }
1673
1674
1675 /**
1676  * Got record. Return if it is an attribute or attestation.
1677  *
1678  * @param cls our attribute iterator
1679  * @param zone zone we are iterating
1680  * @param label label of the records
1681  * @param rd_count record count
1682  * @param rd records
1683  */
1684 static void
1685 attr_iter_cb (void *cls,
1686               const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
1687               const char *label,
1688               unsigned int rd_count,
1689               const struct GNUNET_GNSRECORD_Data *rd)
1690 {
1691   struct AttributeIterator *ai = cls;
1692   struct GNUNET_MQ_Envelope *env;
1693   char *data_tmp;
1694
1695   if (rd_count == 0)
1696   {
1697     GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1698     return;
1699   }
1700   if (rd_count > 1)
1701   {
1702     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE_REF == rd[0].record_type)
1703     {
1704       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705                   "Found Ticket. Ignoring.\n");
1706       GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1707       return;
1708     }
1709     else if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION != rd[0].record_type)
1710     {
1711       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1712                   "Non-Attestation record with multiple entries found: %u\n",
1713                   rd[0].record_type);
1714       GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1715       return;
1716     }
1717   }
1718
1719   for (int i = 0; i<rd_count; i++)
1720   {
1721     if ((GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE != rd[i].record_type) &&
1722         (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION != rd[i].record_type))
1723     {
1724       GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1725       return;
1726     }
1727     // FIXME Send attribute TOGETHER with respective attestation if applicable
1728     if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTRIBUTE == rd[i].record_type)
1729     {
1730       struct AttributeResultMessage *arm;
1731       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attribute under: %s\n",
1732                   label);
1733       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1734                   "Sending ATTRIBUTE_RESULT message\n");
1735       env = GNUNET_MQ_msg_extra (arm,
1736                                  rd[i].data_size,
1737                                  GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_RESULT);
1738       arm->id = htonl (ai->request_id);
1739       arm->attr_len = htons (rd[i].data_size);
1740       GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
1741       data_tmp = (char *) &arm[1];
1742       GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size);
1743       GNUNET_MQ_send (ai->client->mq, env);
1744     }
1745     else
1746     {
1747       if (GNUNET_GNSRECORD_TYPE_RECLAIM_ATTESTATION == rd[i].record_type)
1748       {
1749         struct AttributeResultMessage *arm;
1750         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found attestation under: %s\n",
1751                     label);
1752         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1753                     "Sending ATTESTATION_RESULT message\n");
1754         env = GNUNET_MQ_msg_extra (arm,
1755                                    rd[i].data_size,
1756                                    GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_RESULT);
1757         arm->id = htonl (ai->request_id);
1758         arm->attr_len = htons (rd[i].data_size);
1759         GNUNET_CRYPTO_ecdsa_key_get_public (zone, &arm->identity);
1760         data_tmp = (char *) &arm[1];
1761         GNUNET_memcpy (data_tmp, rd[i].data, rd[i].data_size);
1762         GNUNET_MQ_send (ai->client->mq, env);
1763       }
1764     }
1765   }
1766 }
1767
1768
1769 /**
1770  * Iterate over zone to get attributes
1771  *
1772  * @param cls our client
1773  * @param ais_msg the iteration message to start
1774  */
1775 static void
1776 handle_iteration_start (void *cls,
1777                         const struct AttributeIterationStartMessage *ais_msg)
1778 {
1779   struct IdpClient *idp = cls;
1780   struct AttributeIterator *ai;
1781
1782   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1783               "Received ATTRIBUTE_ITERATION_START message\n");
1784   ai = GNUNET_new (struct AttributeIterator);
1785   ai->request_id = ntohl (ais_msg->id);
1786   ai->client = idp;
1787   ai->identity = ais_msg->identity;
1788
1789   GNUNET_CONTAINER_DLL_insert (idp->attr_iter_head, idp->attr_iter_tail, ai);
1790   ai->ns_it = GNUNET_NAMESTORE_zone_iteration_start (nsh,
1791                                                      &ai->identity,
1792                                                      &attr_iter_error,
1793                                                      ai,
1794                                                      &attr_iter_cb,
1795                                                      ai,
1796                                                      &attr_iter_finished,
1797                                                      ai);
1798   GNUNET_SERVICE_client_continue (idp->client);
1799 }
1800
1801
1802 /**
1803  * Handle iteration stop message from client
1804  *
1805  * @param cls the client
1806  * @param ais_msg the stop message
1807  */
1808 static void
1809 handle_iteration_stop (void *cls,
1810                        const struct AttributeIterationStopMessage *ais_msg)
1811 {
1812   struct IdpClient *idp = cls;
1813   struct AttributeIterator *ai;
1814   uint32_t rid;
1815
1816   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1817               "Received `%s' message\n",
1818               "ATTRIBUTE_ITERATION_STOP");
1819   rid = ntohl (ais_msg->id);
1820   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1821     if (ai->request_id == rid)
1822       break;
1823   if (NULL == ai)
1824   {
1825     GNUNET_break (0);
1826     GNUNET_SERVICE_client_drop (idp->client);
1827     return;
1828   }
1829   GNUNET_CONTAINER_DLL_remove (idp->attr_iter_head, idp->attr_iter_tail, ai);
1830   GNUNET_free (ai);
1831   GNUNET_SERVICE_client_continue (idp->client);
1832 }
1833
1834
1835 /**
1836  * Client requests next attribute from iterator
1837  *
1838  * @param cls the client
1839  * @param ais_msg the message
1840  */
1841 static void
1842 handle_iteration_next (void *cls,
1843                        const struct AttributeIterationNextMessage *ais_msg)
1844 {
1845   struct IdpClient *idp = cls;
1846   struct AttributeIterator *ai;
1847   uint32_t rid;
1848
1849   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1850               "Received ATTRIBUTE_ITERATION_NEXT message\n");
1851   rid = ntohl (ais_msg->id);
1852   for (ai = idp->attr_iter_head; NULL != ai; ai = ai->next)
1853     if (ai->request_id == rid)
1854       break;
1855   if (NULL == ai)
1856   {
1857     GNUNET_break (0);
1858     GNUNET_SERVICE_client_drop (idp->client);
1859     return;
1860   }
1861   GNUNET_NAMESTORE_zone_iterator_next (ai->ns_it, 1);
1862   GNUNET_SERVICE_client_continue (idp->client);
1863 }
1864
1865
1866 /******************************************************
1867 * Ticket iteration
1868 ******************************************************/
1869
1870 /**
1871  * Got a ticket. Return to client
1872  *
1873  * @param cls our ticket iterator
1874  * @param ticket the ticket
1875  */
1876 static void
1877 ticket_iter_cb (void *cls, struct GNUNET_RECLAIM_Ticket *ticket)
1878 {
1879   struct TicketIteration *ti = cls;
1880   struct GNUNET_MQ_Envelope *env;
1881   struct TicketResultMessage *trm;
1882
1883   env = GNUNET_MQ_msg (trm, GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_RESULT);
1884   if (NULL == ticket)
1885   {
1886     /* send empty response to indicate end of list */
1887     GNUNET_CONTAINER_DLL_remove (ti->client->ticket_iter_head,
1888                                  ti->client->ticket_iter_tail,
1889                                  ti);
1890   }
1891   else
1892   {
1893     trm->ticket = *ticket;
1894   }
1895   trm->id = htonl (ti->r_id);
1896   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TICKET_RESULT message\n");
1897   GNUNET_MQ_send (ti->client->mq, env);
1898   if (NULL == ticket)
1899     GNUNET_free (ti);
1900 }
1901
1902
1903 /**
1904  * Client requests a ticket iteration
1905  *
1906  * @param cls the client
1907  * @param tis_msg the iteration request message
1908  */
1909 static void
1910 handle_ticket_iteration_start (
1911   void *cls,
1912   const struct TicketIterationStartMessage *tis_msg)
1913 {
1914   struct IdpClient *client = cls;
1915   struct TicketIteration *ti;
1916
1917   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1918               "Received TICKET_ITERATION_START message\n");
1919   ti = GNUNET_new (struct TicketIteration);
1920   ti->r_id = ntohl (tis_msg->id);
1921   ti->client = client;
1922
1923   GNUNET_CONTAINER_DLL_insert (client->ticket_iter_head,
1924                                client->ticket_iter_tail,
1925                                ti);
1926   ti->iter
1927     = RECLAIM_TICKETS_iteration_start (&tis_msg->identity, &ticket_iter_cb, ti);
1928   GNUNET_SERVICE_client_continue (client->client);
1929 }
1930
1931
1932 /**
1933  * Client has had enough tickets
1934  *
1935  * @param cls the client
1936  * @param tis_msg the stop message
1937  */
1938 static void
1939 handle_ticket_iteration_stop (void *cls,
1940                               const struct TicketIterationStopMessage *tis_msg)
1941 {
1942   struct IdpClient *client = cls;
1943   struct TicketIteration *ti;
1944   uint32_t rid;
1945
1946   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1947               "Received `%s' message\n",
1948               "TICKET_ITERATION_STOP");
1949   rid = ntohl (tis_msg->id);
1950   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1951     if (ti->r_id == rid)
1952       break;
1953   if (NULL == ti)
1954   {
1955     GNUNET_break (0);
1956     GNUNET_SERVICE_client_drop (client->client);
1957     return;
1958   }
1959   RECLAIM_TICKETS_iteration_stop (ti->iter);
1960   GNUNET_CONTAINER_DLL_remove (client->ticket_iter_head,
1961                                client->ticket_iter_tail,
1962                                ti);
1963   GNUNET_free (ti);
1964   GNUNET_SERVICE_client_continue (client->client);
1965 }
1966
1967
1968 /**
1969  * Client requests next result.
1970  *
1971  * @param cls the client
1972  * @param tis_msg the message
1973  */
1974 static void
1975 handle_ticket_iteration_next (void *cls,
1976                               const struct TicketIterationNextMessage *tis_msg)
1977 {
1978   struct IdpClient *client = cls;
1979   struct TicketIteration *ti;
1980   uint32_t rid;
1981
1982   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1983               "Received TICKET_ITERATION_NEXT message\n");
1984   rid = ntohl (tis_msg->id);
1985   for (ti = client->ticket_iter_head; NULL != ti; ti = ti->next)
1986     if (ti->r_id == rid)
1987       break;
1988   if (NULL == ti)
1989   {
1990     GNUNET_break (0);
1991     GNUNET_SERVICE_client_drop (client->client);
1992     return;
1993   }
1994   RECLAIM_TICKETS_iteration_next (ti->iter);
1995   GNUNET_SERVICE_client_continue (client->client);
1996 }
1997
1998
1999 /**
2000  * Main function that will be run
2001  *
2002  * @param cls closure
2003  * @param c the configuration used
2004  * @param server the service handle
2005  */
2006 static void
2007 run (void *cls,
2008      const struct GNUNET_CONFIGURATION_Handle *c,
2009      struct GNUNET_SERVICE_Handle *server)
2010 {
2011   cfg = c;
2012
2013   if (GNUNET_OK != RECLAIM_TICKETS_init (cfg))
2014   {
2015     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2016                 "Unable to initialize TICKETS subsystem.\n");
2017     GNUNET_SCHEDULER_shutdown ();
2018     return;
2019   }
2020   // Connect to identity and namestore services
2021   nsh = GNUNET_NAMESTORE_connect (cfg);
2022   if (NULL == nsh)
2023   {
2024     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
2025                          "error connecting to namestore");
2026   }
2027
2028   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
2029 }
2030
2031
2032 /**
2033  * Called whenever a client is disconnected.
2034  *
2035  * @param cls closure
2036  * @param client identification of the client
2037  * @param app_ctx @a client
2038  */
2039 static void
2040 client_disconnect_cb (void *cls,
2041                       struct GNUNET_SERVICE_Client *client,
2042                       void *app_ctx)
2043 {
2044   struct IdpClient *idp = app_ctx;
2045
2046   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p disconnected\n", client);
2047   GNUNET_CONTAINER_DLL_remove (client_list_head,
2048                                client_list_tail,
2049                                idp);
2050   cleanup_client (idp);
2051 }
2052
2053
2054 /**
2055  * Add a client to our list of active clients.
2056  *
2057  * @param cls NULL
2058  * @param client client to add
2059  * @param mq message queue for @a client
2060  * @return internal namestore client structure for this client
2061  */
2062 static void *
2063 client_connect_cb (void *cls,
2064                    struct GNUNET_SERVICE_Client *client,
2065                    struct GNUNET_MQ_Handle *mq)
2066 {
2067   struct IdpClient *idp;
2068
2069   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", client);
2070   idp = GNUNET_new (struct IdpClient);
2071   idp->client = client;
2072   idp->mq = mq;
2073   GNUNET_CONTAINER_DLL_insert (client_list_head,
2074                                client_list_tail,
2075                                idp);
2076   return idp;
2077 }
2078
2079
2080 /**
2081  * Define "main" method using service macro.
2082  */
2083 GNUNET_SERVICE_MAIN (
2084   "reclaim",
2085   GNUNET_SERVICE_OPTION_NONE,
2086   &run,
2087   &client_connect_cb,
2088   &client_disconnect_cb,
2089   NULL,
2090   GNUNET_MQ_hd_var_size (attribute_store_message,
2091                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_STORE,
2092                          struct AttributeStoreMessage,
2093                          NULL),
2094   GNUNET_MQ_hd_var_size (attestation_store_message,
2095                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_STORE,
2096                          struct AttributeStoreMessage,
2097                          NULL),
2098   GNUNET_MQ_hd_var_size (attribute_delete_message,
2099                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_DELETE,
2100                          struct AttributeDeleteMessage,
2101                          NULL),
2102   GNUNET_MQ_hd_var_size (attestation_delete_message,
2103                          GNUNET_MESSAGE_TYPE_RECLAIM_ATTESTATION_DELETE,
2104                          struct AttributeDeleteMessage,
2105                          NULL),
2106   GNUNET_MQ_hd_fixed_size (iteration_start,
2107                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_START,
2108                            struct AttributeIterationStartMessage,
2109                            NULL),
2110   GNUNET_MQ_hd_fixed_size (iteration_next,
2111                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_NEXT,
2112                            struct AttributeIterationNextMessage,
2113                            NULL),
2114   GNUNET_MQ_hd_fixed_size (iteration_stop,
2115                            GNUNET_MESSAGE_TYPE_RECLAIM_ATTRIBUTE_ITERATION_STOP,
2116                            struct AttributeIterationStopMessage,
2117                            NULL),
2118   GNUNET_MQ_hd_var_size (issue_ticket_message,
2119                          GNUNET_MESSAGE_TYPE_RECLAIM_ISSUE_TICKET,
2120                          struct IssueTicketMessage,
2121                          NULL),
2122   GNUNET_MQ_hd_var_size (consume_ticket_message,
2123                          GNUNET_MESSAGE_TYPE_RECLAIM_CONSUME_TICKET,
2124                          struct ConsumeTicketMessage,
2125                          NULL),
2126   GNUNET_MQ_hd_fixed_size (ticket_iteration_start,
2127                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_START,
2128                            struct TicketIterationStartMessage,
2129                            NULL),
2130   GNUNET_MQ_hd_fixed_size (ticket_iteration_next,
2131                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_NEXT,
2132                            struct TicketIterationNextMessage,
2133                            NULL),
2134   GNUNET_MQ_hd_fixed_size (ticket_iteration_stop,
2135                            GNUNET_MESSAGE_TYPE_RECLAIM_TICKET_ITERATION_STOP,
2136                            struct TicketIterationStopMessage,
2137                            NULL),
2138   GNUNET_MQ_hd_var_size (revoke_ticket_message,
2139                          GNUNET_MESSAGE_TYPE_RECLAIM_REVOKE_TICKET,
2140                          struct RevokeTicketMessage,
2141                          NULL),
2142   GNUNET_MQ_handler_end ());
2143 /* end of gnunet-service-reclaim.c */