-remove debug message
[oweals/gnunet.git] / src / reclaim / gnunet-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-reclaim.c
23  * @brief Identity Provider utility
24  *
25  */
26 #include "platform.h"
27 #include <inttypes.h>
28
29 #include "gnunet_util_lib.h"
30
31 #include "gnunet_identity_service.h"
32 #include "gnunet_namestore_service.h"
33 #include "gnunet_reclaim_service.h"
34 #include "gnunet_signatures.h"
35 /**
36  * return value
37  */
38 static int ret;
39
40 /**
41  * List attribute flag
42  */
43 static int list;
44
45 /**
46  * List attestations flag
47  */
48 static int list_attestations;
49
50 /**
51  * Attestation ID string
52  */
53 static char *attestation_id;
54
55 /**
56  * Attestation ID
57  */
58 static struct GNUNET_RECLAIM_Identifier attestation;
59
60 /**
61  * Attestation name
62  */
63 static char *attestation_name;
64
65 /**
66  * Attestation exists
67  */
68 static int attestation_exists;
69
70 /**
71  * Relying party
72  */
73 static char *rp;
74
75 /**
76  * The attribute
77  */
78 static char *attr_name;
79
80 /**
81  * Attribute value
82  */
83 static char *attr_value;
84
85 /**
86  * Attributes to issue
87  */
88 static char *issue_attrs;
89
90 /**
91  * Ticket to consume
92  */
93 static char *consume_ticket;
94
95 /**
96  * Attribute type
97  */
98 static char *type_str;
99
100 /**
101  * Ticket to revoke
102  */
103 static char *revoke_ticket;
104
105 /**
106  * Ticket listing
107  */
108 static int list_tickets;
109
110 /**
111  * Ego name
112  */
113 static char *ego_name;
114
115 /**
116  * Identity handle
117  */
118 static struct GNUNET_IDENTITY_Handle *identity_handle;
119
120 /**
121  * reclaim handle
122  */
123 static struct GNUNET_RECLAIM_Handle *reclaim_handle;
124
125 /**
126  * reclaim operation
127  */
128 static struct GNUNET_RECLAIM_Operation *reclaim_op;
129
130 /**
131  * Attribute iterator
132  */
133 static struct GNUNET_RECLAIM_AttributeIterator *attr_iterator;
134
135 /**
136  * Attestation iterator
137  */
138 static struct GNUNET_RECLAIM_AttestationIterator *attest_iterator;
139
140
141 /**
142  * Ticket iterator
143  */
144 static struct GNUNET_RECLAIM_TicketIterator *ticket_iterator;
145
146 /**
147  * Master ABE key
148  */
149 static struct GNUNET_CRYPTO_AbeMasterKey *abe_key;
150
151 /**
152  * ego private key
153  */
154 static const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey;
155
156 /**
157  * rp public key
158  */
159 static struct GNUNET_CRYPTO_EcdsaPublicKey rp_key;
160
161 /**
162  * Ticket to consume
163  */
164 static struct GNUNET_RECLAIM_Ticket ticket;
165
166 /**
167  * Attribute list
168  */
169 static struct GNUNET_RECLAIM_AttributeList *attr_list;
170
171 /**
172  * Attribute expiration interval
173  */
174 static struct GNUNET_TIME_Relative exp_interval;
175
176 /**
177  * Timeout task
178  */
179 static struct GNUNET_SCHEDULER_Task *timeout;
180
181 /**
182  * Cleanup task
183  */
184 static struct GNUNET_SCHEDULER_Task *cleanup_task;
185
186 /**
187  * Claim to store
188  */
189 struct GNUNET_RECLAIM_Attribute *claim;
190
191 /**
192  * Claim to delete
193  */
194 static char *attr_delete;
195
196 /**
197  * Claim object to delete
198  */
199 static struct GNUNET_RECLAIM_Attribute *attr_to_delete;
200
201 static void
202 do_cleanup (void *cls)
203 {
204   cleanup_task = NULL;
205   if (NULL != timeout)
206     GNUNET_SCHEDULER_cancel (timeout);
207   if (NULL != reclaim_op)
208     GNUNET_RECLAIM_cancel (reclaim_op);
209   if (NULL != attr_iterator)
210     GNUNET_RECLAIM_get_attributes_stop (attr_iterator);
211   if (NULL != attest_iterator)
212     GNUNET_RECLAIM_get_attestations_stop (attest_iterator);
213   if (NULL != ticket_iterator)
214     GNUNET_RECLAIM_ticket_iteration_stop (ticket_iterator);
215   if (NULL != reclaim_handle)
216     GNUNET_RECLAIM_disconnect (reclaim_handle);
217   if (NULL != identity_handle)
218     GNUNET_IDENTITY_disconnect (identity_handle);
219   if (NULL != abe_key)
220     GNUNET_free (abe_key);
221   if (NULL != attr_list)
222     GNUNET_free (attr_list);
223   if (NULL != attr_to_delete)
224     GNUNET_free (attr_to_delete);
225 }
226
227
228 static void
229 ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
230 {
231   char *ticket_str;
232
233   reclaim_op = NULL;
234   if (NULL != ticket)
235   {
236     ticket_str =
237       GNUNET_STRINGS_data_to_string_alloc (ticket,
238                                            sizeof(
239                                              struct GNUNET_RECLAIM_Ticket));
240     printf ("%s\n", ticket_str);
241     GNUNET_free (ticket_str);
242   }
243   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
244 }
245
246
247 static void
248 store_cont (void *cls, int32_t success, const char *emsg)
249 {
250   reclaim_op = NULL;
251   if (GNUNET_SYSERR == success)
252   {
253     fprintf (stderr, "%s\n", emsg);
254   }
255   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
256 }
257
258
259 static void
260 process_attrs (void *cls,
261                const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
262                const struct GNUNET_RECLAIM_Attribute *attr,
263                const struct GNUNET_RECLAIM_Attestation *attest)
264 {
265   char *value_str;
266   char *id;
267   const char *attr_type;
268
269   if (NULL == identity)
270   {
271     reclaim_op = NULL;
272     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
273     return;
274   }
275   if (NULL == attr)
276   {
277     ret = 1;
278     return;
279   }
280   attr_type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
281   id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
282   value_str = NULL;
283   if (NULL == attest)
284   {
285     value_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
286                                                           attr->data,
287                                                           attr->data_size);
288   }
289   else
290   {
291     struct GNUNET_RECLAIM_AttributeListEntry *ale;
292     struct GNUNET_RECLAIM_AttributeList *al
293       = GNUNET_RECLAIM_attestation_get_attributes (attest);
294
295     for (ale = al->list_head; NULL != ale; ale = ale->next)
296     {
297       if (0 != strncmp (attr->data, ale->attribute->name, attr->data_size))
298         continue;
299       value_str
300         = GNUNET_RECLAIM_attribute_value_to_string (ale->attribute->type,
301                                                     ale->attribute->
302                                                     data,
303                                                     ale->attribute->
304                                                     data_size);
305       break;
306     }
307   }
308   fprintf (stdout,
309            "Name: %s; Value: %s (%s); Flag %u; ID: %s %s\n",
310            attr->name,
311            (NULL != value_str) ? value_str : "???",
312            attr_type,
313            attr->flag,
314            id,
315            (NULL == attest) ? "" : "(ATTESTED)");
316   GNUNET_free_non_null (value_str);
317   GNUNET_free (id);
318 }
319
320
321 static void
322 ticket_iter_err (void *cls)
323 {
324   ticket_iterator = NULL;
325   fprintf (stderr, "Failed to iterate over tickets\n");
326   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
327 }
328
329
330 static void
331 ticket_iter_fin (void *cls)
332 {
333   ticket_iterator = NULL;
334   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
335 }
336
337
338 static void
339 ticket_iter (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
340 {
341   char *aud;
342   char *ref;
343   char *tkt;
344
345   aud =
346     GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
347                                          sizeof(struct
348                                                 GNUNET_CRYPTO_EcdsaPublicKey));
349   ref = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(ticket->rnd));
350   tkt =
351     GNUNET_STRINGS_data_to_string_alloc (ticket,
352                                          sizeof(struct GNUNET_RECLAIM_Ticket));
353   fprintf (stdout, "Ticket: %s | ID: %s | Audience: %s\n", tkt, ref, aud);
354   GNUNET_free (aud);
355   GNUNET_free (ref);
356   GNUNET_free (tkt);
357   GNUNET_RECLAIM_ticket_iteration_next (ticket_iterator);
358 }
359
360
361 static void
362 iter_error (void *cls)
363 {
364   attr_iterator = NULL;
365   attest_iterator = NULL;
366   fprintf (stderr, "Failed\n");
367
368   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
369 }
370
371
372 static void
373 timeout_task (void *cls)
374 {
375   timeout = NULL;
376   ret = 1;
377   fprintf (stderr, "Timeout\n");
378   if (NULL == cleanup_task)
379     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
380 }
381
382
383 static void
384 process_rvk (void *cls, int success, const char *msg)
385 {
386   reclaim_op = NULL;
387   if (GNUNET_OK != success)
388   {
389     fprintf (stderr, "Revocation failed.\n");
390     ret = 1;
391   }
392   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
393 }
394
395
396 static void
397 process_delete (void *cls, int success, const char *msg)
398 {
399   reclaim_op = NULL;
400   if (GNUNET_OK != success)
401   {
402     fprintf (stderr, "Deletion failed.\n");
403     ret = 1;
404   }
405   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
406 }
407
408
409 static void
410 iter_finished (void *cls)
411 {
412   char *data;
413   size_t data_size;
414   int type;
415
416   attr_iterator = NULL;
417   if (list)
418   {
419     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
420     return;
421   }
422
423   if (issue_attrs)
424   {
425     reclaim_op = GNUNET_RECLAIM_ticket_issue (reclaim_handle,
426                                               pkey,
427                                               &rp_key,
428                                               attr_list,
429                                               &ticket_issue_cb,
430                                               NULL);
431     return;
432   }
433   if (consume_ticket)
434   {
435     reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle,
436                                                 pkey,
437                                                 &ticket,
438                                                 &process_attrs,
439                                                 NULL);
440     timeout = GNUNET_SCHEDULER_add_delayed (
441       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
442       &timeout_task,
443       NULL);
444     return;
445   }
446   if (revoke_ticket)
447   {
448     reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle,
449                                                pkey,
450                                                &ticket,
451                                                &process_rvk,
452                                                NULL);
453     return;
454   }
455   if (attr_delete)
456   {
457     if (NULL == attr_to_delete)
458     {
459       fprintf (stdout, "No such attribute ``%s''\n", attr_delete);
460       return;
461     }
462     reclaim_op = GNUNET_RECLAIM_attribute_delete (reclaim_handle,
463                                                   pkey,
464                                                   attr_to_delete,
465                                                   &process_delete,
466                                                   NULL);
467     return;
468   }
469   if (attr_name)
470   {
471     if (NULL == type_str)
472       type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
473     else
474       type = GNUNET_RECLAIM_attribute_typename_to_number (type_str);
475
476     GNUNET_assert (GNUNET_SYSERR !=
477                    GNUNET_RECLAIM_attribute_string_to_value (type,
478                                                              attr_value,
479                                                              (void **) &data,
480                                                              &data_size));
481     if (NULL != claim)
482     {
483       claim->type = type;
484       claim->data = data;
485       claim->data_size = data_size;
486     }
487     else
488     {
489       claim =
490         GNUNET_RECLAIM_attribute_new (attr_name, NULL, type, data, data_size);
491     }
492     if (NULL != attestation_id)
493     {
494       claim->attestation = attestation;
495     }
496     reclaim_op = GNUNET_RECLAIM_attribute_store (reclaim_handle,
497                                                  pkey,
498                                                  claim,
499                                                  &exp_interval,
500                                                  &store_cont,
501                                                  NULL);
502     GNUNET_free (data);
503     GNUNET_free (claim);
504     return;
505   }
506   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
507 }
508
509
510 static void
511 iter_cb (void *cls,
512          const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
513          const struct GNUNET_RECLAIM_Attribute *attr)
514 {
515   struct GNUNET_RECLAIM_AttributeListEntry *le;
516   char *attrs_tmp;
517   char *attr_str;
518   char *label;
519   char *id;
520   const char *attr_type;
521
522   if ((NULL != attr_name) && (NULL != claim))
523   {
524     if (0 == strcasecmp (attr_name, attr->name))
525     {
526       claim = GNUNET_RECLAIM_attribute_new (attr->name,
527                                             &attr->attestation,
528                                             attr->type,
529                                             attr->data,
530                                             attr->data_size);
531     }
532   }
533   else if (issue_attrs)
534   {
535     attrs_tmp = GNUNET_strdup (issue_attrs);
536     attr_str = strtok (attrs_tmp, ",");
537     while (NULL != attr_str)
538     {
539       if (0 != strcasecmp (attr_str, attr->name))
540       {
541         attr_str = strtok (NULL, ",");
542         continue;
543       }
544       le = GNUNET_new (struct GNUNET_RECLAIM_AttributeListEntry);
545       le->attribute = GNUNET_RECLAIM_attribute_new (attr->name,
546                                                     &attr->attestation,
547                                                     attr->type,
548                                                     attr->data,
549                                                     attr->data_size);
550       le->attribute->flag = attr->flag;
551       le->attribute->id = attr->id;
552       GNUNET_CONTAINER_DLL_insert (attr_list->list_head,
553                                    attr_list->list_tail,
554                                    le);
555       break;
556     }
557     GNUNET_free (attrs_tmp);
558   }
559   else if (attr_delete && (NULL == attr_to_delete))
560   {
561     label = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
562     if (0 == strcasecmp (attr_delete, label))
563     {
564       attr_to_delete = GNUNET_RECLAIM_attribute_new (attr->name,
565                                                      &attr->attestation,
566                                                      attr->type,
567                                                      attr->data,
568                                                      attr->data_size);
569       attr_to_delete->id = attr->id;
570     }
571     GNUNET_free (label);
572   }
573   else if (list)
574   {
575     attr_str = GNUNET_RECLAIM_attribute_value_to_string (attr->type,
576                                                          attr->data,
577                                                          attr->data_size);
578     attr_type = GNUNET_RECLAIM_attribute_number_to_typename (attr->type);
579     id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(attr->id));
580     if (GNUNET_YES == GNUNET_RECLAIM_id_is_zero (&attr->attestation))
581     {
582       fprintf (stdout,
583                "%s: ``%s'' (%s); ID: %s\n",
584                attr->name,
585                attr_str,
586                attr_type,
587                id);
588     }
589     else
590     {
591       char *attest_id =
592         GNUNET_STRINGS_data_to_string_alloc (&attr->attestation,
593                                              sizeof(attr->attestation));
594       fprintf (stdout,
595                "%s: <``%s'' in attestation %s> (%s); ID: %s\n",
596                attr->name,
597                attr_str,
598                attest_id,
599                attr_type,
600                id);
601       GNUNET_free (attest_id);
602
603     }
604     GNUNET_free (id);
605   }
606   GNUNET_RECLAIM_get_attributes_next (attr_iterator);
607 }
608
609
610 static void
611 attest_iter_finished (void *cls)
612 {
613   attest_iterator = NULL;
614
615   // Add new attestation
616   if ((NULL != attestation_name) &&
617       (NULL != attr_value))
618   {
619     struct GNUNET_RECLAIM_Attestation *attestation =
620       GNUNET_RECLAIM_attestation_new (attestation_name,
621                                       GNUNET_RECLAIM_ATTESTATION_TYPE_JWT, // FIXME hardcoded
622                                       attr_value,
623                                       strlen (attr_value));
624     reclaim_op = GNUNET_RECLAIM_attestation_store (reclaim_handle,
625                                                    pkey,
626                                                    attestation,
627                                                    &exp_interval,
628                                                    store_cont,
629                                                    NULL);
630     return;
631
632   }
633   if (list_attestations)
634   {
635     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
636     return;
637   }
638   attr_iterator = GNUNET_RECLAIM_get_attributes_start (reclaim_handle,
639                                                        pkey,
640                                                        &iter_error,
641                                                        NULL,
642                                                        &iter_cb,
643                                                        NULL,
644                                                        &iter_finished,
645                                                        NULL);
646
647 }
648
649
650 static void
651 attest_iter_cb (void *cls,
652                 const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
653                 const struct GNUNET_RECLAIM_Attestation *attest)
654 {
655   char *attest_str;
656   char *attr_str;
657   char *id;
658   const char *attest_type;
659   struct GNUNET_RECLAIM_AttributeListEntry *ale;
660
661   if (GNUNET_YES == GNUNET_RECLAIM_id_is_equal (&attestation,
662                                                 &attest->id))
663     attestation_exists = GNUNET_YES;
664   if (list_attestations)
665   {
666     attest_str = GNUNET_RECLAIM_attestation_value_to_string (attest->type,
667                                                              attest->data,
668                                                              attest->data_size);
669     attest_type = GNUNET_RECLAIM_attestation_number_to_typename (attest->type);
670     id = GNUNET_STRINGS_data_to_string_alloc (&attest->id, sizeof(attest->id));
671     fprintf (stdout,
672              "%s: ``%s'' (%s); ID: %s\n",
673              attest->name,
674              attest_str,
675              attest_type,
676              id);
677     struct GNUNET_RECLAIM_AttributeList *attrs =
678       GNUNET_RECLAIM_attestation_get_attributes (attest);
679     if (NULL != attrs)
680     {
681       fprintf (stdout,
682                "\t Attributes:\n");
683       for (ale = attrs->list_head; NULL != ale; ale = ale->next)
684       {
685         attr_str = GNUNET_RECLAIM_attribute_value_to_string (
686           ale->attribute->type,
687           ale->attribute->
688           data,
689           ale->attribute->
690           data_size);
691
692         fprintf (stdout,
693                  "\t %s: %s\n", ale->attribute->name, attr_str);
694         GNUNET_free (attr_str);
695       }
696       GNUNET_RECLAIM_attribute_list_destroy (attrs);
697     }
698     GNUNET_free (id);
699   }
700   GNUNET_RECLAIM_get_attestations_next (attest_iterator);
701 }
702
703
704 static void
705 start_process ()
706 {
707   if (NULL == pkey)
708   {
709     fprintf (stderr, "Ego %s not found\n", ego_name);
710     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
711     return;
712   }
713   attestation = GNUNET_RECLAIM_ID_ZERO;
714   if (NULL != attestation_id)
715     GNUNET_STRINGS_string_to_data (attestation_id,
716                                    strlen (attestation_id),
717                                    &attestation, sizeof(attestation));
718   attestation_exists = GNUNET_NO;
719   if (list_tickets)
720   {
721     ticket_iterator = GNUNET_RECLAIM_ticket_iteration_start (reclaim_handle,
722                                                              pkey,
723                                                              &ticket_iter_err,
724                                                              NULL,
725                                                              &ticket_iter,
726                                                              NULL,
727                                                              &ticket_iter_fin,
728                                                              NULL);
729     return;
730   }
731
732   if ((NULL != rp) &&
733       (GNUNET_OK !=
734        GNUNET_CRYPTO_ecdsa_public_key_from_string (rp, strlen (rp), &rp_key)) )
735   {
736     fprintf (stderr, "%s is not a public key!\n", rp);
737     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
738     return;
739   }
740   if (NULL != consume_ticket)
741     GNUNET_STRINGS_string_to_data (consume_ticket,
742                                    strlen (consume_ticket),
743                                    &ticket,
744                                    sizeof(struct GNUNET_RECLAIM_Ticket));
745   if (NULL != revoke_ticket)
746     GNUNET_STRINGS_string_to_data (revoke_ticket,
747                                    strlen (revoke_ticket),
748                                    &ticket,
749                                    sizeof(struct GNUNET_RECLAIM_Ticket));
750
751   attr_list = GNUNET_new (struct GNUNET_RECLAIM_AttributeList);
752   claim = NULL;
753   attest_iterator = GNUNET_RECLAIM_get_attestations_start (reclaim_handle,
754                                                            pkey,
755                                                            &iter_error,
756                                                            NULL,
757                                                            &attest_iter_cb,
758                                                            NULL,
759                                                            &
760                                                            attest_iter_finished,
761                                                            NULL);
762
763 }
764
765
766 static int init = GNUNET_YES;
767
768 static void
769 ego_cb (void *cls,
770         struct GNUNET_IDENTITY_Ego *ego,
771         void **ctx,
772         const char *name)
773 {
774   if (NULL == name)
775   {
776     if (GNUNET_YES == init)
777     {
778       init = GNUNET_NO;
779       start_process ();
780     }
781     return;
782   }
783   if (0 != strcmp (name, ego_name))
784     return;
785   pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
786 }
787
788
789 static void
790 run (void *cls,
791      char *const *args,
792      const char *cfgfile,
793      const struct GNUNET_CONFIGURATION_Handle *c)
794 {
795   ret = 0;
796   if (NULL == ego_name)
797   {
798     ret = 1;
799     fprintf (stderr, _ ("Ego is required\n"));
800     return;
801   }
802
803   if ((NULL == attr_value) && (NULL != attr_name))
804   {
805     ret = 1;
806     fprintf (stderr, _ ("Attribute value missing!\n"));
807     return;
808   }
809
810   if ((NULL == rp) && (NULL != issue_attrs))
811   {
812     ret = 1;
813     fprintf (stderr, _ ("Requesting party key is required!\n"));
814     return;
815   }
816
817   reclaim_handle = GNUNET_RECLAIM_connect (c);
818   // Get Ego
819   identity_handle = GNUNET_IDENTITY_connect (c, &ego_cb, NULL);
820 }
821
822
823 int
824 main (int argc, char *const argv[])
825 {
826   exp_interval = GNUNET_TIME_UNIT_HOURS;
827   struct GNUNET_GETOPT_CommandLineOption options[] = {
828     GNUNET_GETOPT_option_string ('a',
829                                  "add",
830                                  "NAME",
831                                  gettext_noop ("Add an attribute NAME"),
832                                  &attr_name),
833     GNUNET_GETOPT_option_string ('d',
834                                  "delete",
835                                  "ID",
836                                  gettext_noop ("Delete the attribute with ID"),
837                                  &attr_delete),
838     GNUNET_GETOPT_option_string ('V',
839                                  "value",
840                                  "VALUE",
841                                  gettext_noop ("The attribute VALUE"),
842                                  &attr_value),
843     GNUNET_GETOPT_option_string ('e',
844                                  "ego",
845                                  "EGO",
846                                  gettext_noop ("The EGO to use"),
847                                  &ego_name),
848     GNUNET_GETOPT_option_string ('r',
849                                  "rp",
850                                  "RP",
851                                  gettext_noop (
852                                    "Specify the relying party for issue"),
853                                  &rp),
854     GNUNET_GETOPT_option_flag ('D',
855                                "dump",
856                                gettext_noop ("List attributes for EGO"),
857                                &list),
858     GNUNET_GETOPT_option_flag ('A',
859                                "attestations",
860                                gettext_noop ("List attestations for EGO"),
861                                &list_attestations),
862     GNUNET_GETOPT_option_string ('I',
863                                  "Attestation ID",
864                                  "ATTESTATION_ID",
865                                  gettext_noop (
866                                    "Attestation to use for attribute"),
867                                  &attestation_id),
868     GNUNET_GETOPT_option_string ('N',
869                                  "attestation-name",
870                                  "NAME",
871                                  gettext_noop ("Attestation name"),
872                                  &attestation_name),
873     GNUNET_GETOPT_option_string ('i',
874                                  "issue",
875                                  "A1,A2,...",
876                                  gettext_noop (
877                                    "Issue a ticket for a set of attributes separated by comma"),
878                                  &issue_attrs),
879     GNUNET_GETOPT_option_string ('C',
880                                  "consume",
881                                  "TICKET",
882                                  gettext_noop ("Consume a ticket"),
883                                  &consume_ticket),
884     GNUNET_GETOPT_option_string ('R',
885                                  "revoke",
886                                  "TICKET",
887                                  gettext_noop ("Revoke a ticket"),
888                                  &revoke_ticket),
889     GNUNET_GETOPT_option_string ('t',
890                                  "type",
891                                  "TYPE",
892                                  gettext_noop ("Type of attribute"),
893                                  &type_str),
894     GNUNET_GETOPT_option_flag ('T',
895                                "tickets",
896                                gettext_noop ("List tickets of ego"),
897                                &list_tickets),
898     GNUNET_GETOPT_option_relative_time ('E',
899                                         "expiration",
900                                         "INTERVAL",
901                                         gettext_noop (
902                                           "Expiration interval of the attribute"),
903                                         &exp_interval),
904
905     GNUNET_GETOPT_OPTION_END
906   };
907   if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
908                                        argv,
909                                        "gnunet-reclaim",
910                                        _ ("re:claimID command line tool"),
911                                        options,
912                                        &run,
913                                        NULL))
914     return 1;
915   else
916     return ret;
917 }