better debug output
[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  * Relying party
47  */
48 static char *rp;
49
50 /**
51  * The attribute
52  */
53 static char *attr_name;
54
55 /**
56  * Attribute value
57  */
58 static char *attr_value;
59
60 /**
61  * Attributes to issue
62  */
63 static char *issue_attrs;
64
65 /**
66  * Ticket to consume
67  */
68 static char *consume_ticket;
69
70 /**
71  * Attribute type
72  */
73 static char *type_str;
74
75 /**
76  * Ticket to revoke
77  */
78 static char *revoke_ticket;
79
80 /**
81  * Ticket listing
82  */
83 static int list_tickets;
84
85 /**
86  * Ego name
87  */
88 static char *ego_name;
89
90 /**
91  * Identity handle
92  */
93 static struct GNUNET_IDENTITY_Handle *identity_handle;
94
95 /**
96  * reclaim handle
97  */
98 static struct GNUNET_RECLAIM_Handle *reclaim_handle;
99
100 /**
101  * reclaim operation
102  */
103 static struct GNUNET_RECLAIM_Operation *reclaim_op;
104
105 /**
106  * Attribute iterator
107  */
108 static struct GNUNET_RECLAIM_AttributeIterator *attr_iterator;
109
110 /**
111  * Ticket iterator
112  */
113 static struct GNUNET_RECLAIM_TicketIterator *ticket_iterator;
114
115 /**
116  * Master ABE key
117  */
118 static struct GNUNET_CRYPTO_AbeMasterKey *abe_key;
119
120 /**
121  * ego private key
122  */
123 static const struct GNUNET_CRYPTO_EcdsaPrivateKey *pkey;
124
125 /**
126  * rp public key
127  */
128 static struct GNUNET_CRYPTO_EcdsaPublicKey rp_key;
129
130 /**
131  * Ticket to consume
132  */
133 static struct GNUNET_RECLAIM_Ticket ticket;
134
135 /**
136  * Attribute list
137  */
138 static struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList *attr_list;
139
140 /**
141  * Attribute expiration interval
142  */
143 static struct GNUNET_TIME_Relative exp_interval;
144
145 /**
146  * Timeout task
147  */
148 static struct GNUNET_SCHEDULER_Task *timeout;
149
150 /**
151  * Cleanup task
152  */
153 static struct GNUNET_SCHEDULER_Task *cleanup_task;
154
155 /**
156  * Claim to store
157  */
158 struct GNUNET_RECLAIM_ATTRIBUTE_Claim *claim;
159
160 /**
161  * Claim to delete
162  */
163 static char *attr_delete;
164
165 /**
166  * Claim object to delete
167  */
168 static struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr_to_delete;
169
170 static void
171 do_cleanup (void *cls)
172 {
173   cleanup_task = NULL;
174   if (NULL != timeout)
175     GNUNET_SCHEDULER_cancel (timeout);
176   if (NULL != reclaim_op)
177     GNUNET_RECLAIM_cancel (reclaim_op);
178   if (NULL != attr_iterator)
179     GNUNET_RECLAIM_get_attributes_stop (attr_iterator);
180   if (NULL != ticket_iterator)
181     GNUNET_RECLAIM_ticket_iteration_stop (ticket_iterator);
182   if (NULL != reclaim_handle)
183     GNUNET_RECLAIM_disconnect (reclaim_handle);
184   if (NULL != identity_handle)
185     GNUNET_IDENTITY_disconnect (identity_handle);
186   if (NULL != abe_key)
187     GNUNET_free (abe_key);
188   if (NULL != attr_list)
189     GNUNET_free (attr_list);
190   if (NULL != attr_to_delete)
191     GNUNET_free (attr_to_delete);
192 }
193
194 static void
195 ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
196 {
197   char *ticket_str;
198   reclaim_op = NULL;
199   if (NULL != ticket)
200   {
201     ticket_str =
202       GNUNET_STRINGS_data_to_string_alloc (ticket,
203                                            sizeof (
204                                              struct GNUNET_RECLAIM_Ticket));
205     printf ("%s\n", ticket_str);
206     GNUNET_free (ticket_str);
207   }
208   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
209 }
210
211 static void
212 store_attr_cont (void *cls, int32_t success, const char *emsg)
213 {
214   reclaim_op = NULL;
215   if (GNUNET_SYSERR == success)
216   {
217     fprintf (stderr, "%s\n", emsg);
218   }
219   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
220 }
221
222 static void
223 process_attrs (void *cls,
224                const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
225                const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
226 {
227   char *value_str;
228   char *id;
229   const char *attr_type;
230
231   if (NULL == identity)
232   {
233     reclaim_op = NULL;
234     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
235     return;
236   }
237   if (NULL == attr)
238   {
239     ret = 1;
240     return;
241   }
242   value_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
243                                                         attr->data,
244                                                         attr->data_size);
245   attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
246   id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
247   fprintf (stdout,
248            "Name: %s; Value: %s (%s); Version %u; ID: %s\n",
249            attr->name,
250            value_str,
251            attr_type,
252            attr->version,
253            id);
254   GNUNET_free (id);
255 }
256
257 static void
258 ticket_iter_err (void *cls)
259 {
260   ticket_iterator = NULL;
261   fprintf (stderr, "Failed to iterate over tickets\n");
262   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
263 }
264
265 static void
266 ticket_iter_fin (void *cls)
267 {
268   ticket_iterator = NULL;
269   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
270 }
271
272 static void
273 ticket_iter (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
274 {
275   char *aud;
276   char *ref;
277   char *tkt;
278
279   aud =
280     GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
281                                          sizeof (struct
282                                                  GNUNET_CRYPTO_EcdsaPublicKey));
283   ref = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
284   tkt =
285     GNUNET_STRINGS_data_to_string_alloc (ticket,
286                                          sizeof (struct GNUNET_RECLAIM_Ticket));
287   fprintf (stdout, "Ticket: %s | ID: %s | Audience: %s\n", tkt, ref, aud);
288   GNUNET_free (aud);
289   GNUNET_free (ref);
290   GNUNET_free (tkt);
291   GNUNET_RECLAIM_ticket_iteration_next (ticket_iterator);
292 }
293
294 static void
295 iter_error (void *cls)
296 {
297   attr_iterator = NULL;
298   fprintf (stderr, "Failed to iterate over attributes\n");
299   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
300 }
301
302 static void
303 timeout_task (void *cls)
304 {
305   timeout = NULL;
306   ret = 1;
307   fprintf (stderr, "Timeout\n");
308   if (NULL == cleanup_task)
309     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
310 }
311
312 static void
313 process_rvk (void *cls, int success, const char *msg)
314 {
315   reclaim_op = NULL;
316   if (GNUNET_OK != success)
317   {
318     fprintf (stderr, "Revocation failed.\n");
319     ret = 1;
320   }
321   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
322 }
323
324
325 static void
326 process_delete (void *cls, int success, const char *msg)
327 {
328   reclaim_op = NULL;
329   if (GNUNET_OK != success)
330   {
331     fprintf (stderr, "Deletion failed.\n");
332     ret = 1;
333   }
334   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
335 }
336
337
338 static void
339 iter_finished (void *cls)
340 {
341   char *data;
342   size_t data_size;
343   int type;
344
345   attr_iterator = NULL;
346   if (list)
347   {
348     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
349     return;
350   }
351
352   if (issue_attrs)
353   {
354     reclaim_op = GNUNET_RECLAIM_ticket_issue (reclaim_handle,
355                                               pkey,
356                                               &rp_key,
357                                               attr_list,
358                                               &ticket_issue_cb,
359                                               NULL);
360     return;
361   }
362   if (consume_ticket)
363   {
364     reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle,
365                                                 pkey,
366                                                 &ticket,
367                                                 &process_attrs,
368                                                 NULL);
369     timeout = GNUNET_SCHEDULER_add_delayed (
370       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
371       &timeout_task,
372       NULL);
373     return;
374   }
375   if (revoke_ticket)
376   {
377     reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle,
378                                                pkey,
379                                                &ticket,
380                                                &process_rvk,
381                                                NULL);
382     return;
383   }
384   if (attr_delete)
385   {
386     if (NULL == attr_to_delete)
387     {
388       fprintf (stdout, "No such attribute ``%s''\n", attr_delete);
389       return;
390     }
391     reclaim_op = GNUNET_RECLAIM_attribute_delete (reclaim_handle,
392                                                   pkey,
393                                                   attr_to_delete,
394                                                   &process_delete,
395                                                   NULL);
396     return;
397   }
398   if (attr_name)
399   {
400     if (NULL == type_str)
401       type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
402     else
403       type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str);
404
405     GNUNET_assert (GNUNET_SYSERR !=
406                    GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,
407                                                              attr_value,
408                                                              (void **) &data,
409                                                              &data_size));
410     if (NULL != claim)
411     {
412       claim->type = type;
413       claim->data = data;
414       claim->data_size = data_size;
415     }
416     else
417     {
418       claim =
419         GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr_name, type, data, data_size);
420     }
421     reclaim_op = GNUNET_RECLAIM_attribute_store (reclaim_handle,
422                                                  pkey,
423                                                  claim,
424                                                  &exp_interval,
425                                                  &store_attr_cont,
426                                                  NULL);
427     GNUNET_free (data);
428     GNUNET_free (claim);
429     return;
430   }
431   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
432 }
433
434 static void
435 iter_cb (void *cls,
436          const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
437          const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
438 {
439   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
440   char *attrs_tmp;
441   char *attr_str;
442   char *label;
443   char *id;
444   const char *attr_type;
445
446   if ((NULL != attr_name) && (NULL != claim))
447   {
448     if (0 == strcasecmp (attr_name, attr->name))
449     {
450       claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
451                                                   attr->type,
452                                                   attr->data,
453                                                   attr->data_size);
454     }
455   }
456   else if (issue_attrs)
457   {
458     attrs_tmp = GNUNET_strdup (issue_attrs);
459     attr_str = strtok (attrs_tmp, ",");
460     while (NULL != attr_str)
461     {
462       if (0 != strcasecmp (attr_str, attr->name))
463       {
464         attr_str = strtok (NULL, ",");
465         continue;
466       }
467       le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
468       le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
469                                                       attr->type,
470                                                       attr->data,
471                                                       attr->data_size);
472       le->claim->version = attr->version;
473       le->claim->id = attr->id;
474       GNUNET_CONTAINER_DLL_insert (attr_list->list_head,
475                                    attr_list->list_tail,
476                                    le);
477       break;
478     }
479     GNUNET_free (attrs_tmp);
480   }
481   else if (attr_delete && (NULL == attr_to_delete))
482   {
483     label = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
484     if (0 == strcasecmp (attr_delete, label))
485     {
486       attr_to_delete = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
487                                                            attr->type,
488                                                            attr->data,
489                                                            attr->data_size);
490       attr_to_delete->id = attr->id;
491     }
492     GNUNET_free (label);
493   }
494   else if (list)
495   {
496     attr_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
497                                                          attr->data,
498                                                          attr->data_size);
499     attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
500     id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof (uint64_t));
501     fprintf (stdout,
502              "Name: %s; Value: %s (%s); Version %u; ID: %s\n",
503              attr->name,
504              attr_str,
505              attr_type,
506              attr->version,
507              id);
508     GNUNET_free (id);
509   }
510   GNUNET_RECLAIM_get_attributes_next (attr_iterator);
511 }
512
513 static void
514 start_process ()
515 {
516   if (NULL == pkey)
517   {
518     fprintf (stderr, "Ego %s not found\n", ego_name);
519     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
520     return;
521   }
522
523   if (list_tickets)
524   {
525     ticket_iterator = GNUNET_RECLAIM_ticket_iteration_start (reclaim_handle,
526                                                              pkey,
527                                                              &ticket_iter_err,
528                                                              NULL,
529                                                              &ticket_iter,
530                                                              NULL,
531                                                              &ticket_iter_fin,
532                                                              NULL);
533     return;
534   }
535
536   if ((NULL != rp) &&
537       GNUNET_OK !=
538         GNUNET_CRYPTO_ecdsa_public_key_from_string (rp, strlen (rp), &rp_key))
539   {
540     fprintf (stderr, "%s is not a public key!\n", rp);
541     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
542     return;
543   }
544   if (NULL != consume_ticket)
545     GNUNET_STRINGS_string_to_data (consume_ticket,
546                                    strlen (consume_ticket),
547                                    &ticket,
548                                    sizeof (struct GNUNET_RECLAIM_Ticket));
549   if (NULL != revoke_ticket)
550     GNUNET_STRINGS_string_to_data (revoke_ticket,
551                                    strlen (revoke_ticket),
552                                    &ticket,
553                                    sizeof (struct GNUNET_RECLAIM_Ticket));
554
555   attr_list = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
556   claim = NULL;
557   attr_iterator = GNUNET_RECLAIM_get_attributes_start (reclaim_handle,
558                                                        pkey,
559                                                        &iter_error,
560                                                        NULL,
561                                                        &iter_cb,
562                                                        NULL,
563                                                        &iter_finished,
564                                                        NULL);
565 }
566
567 static int init = GNUNET_YES;
568
569 static void
570 ego_cb (void *cls,
571         struct GNUNET_IDENTITY_Ego *ego,
572         void **ctx,
573         const char *name)
574 {
575   if (NULL == name)
576   {
577     if (GNUNET_YES == init)
578     {
579       init = GNUNET_NO;
580       start_process ();
581     }
582     return;
583   }
584   if (0 != strcmp (name, ego_name))
585     return;
586   pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
587 }
588
589
590 static void
591 run (void *cls,
592      char *const *args,
593      const char *cfgfile,
594      const struct GNUNET_CONFIGURATION_Handle *c)
595 {
596   ret = 0;
597   if (NULL == ego_name)
598   {
599     ret = 1;
600     fprintf (stderr, _ ("Ego is required\n"));
601     return;
602   }
603
604   if ((NULL == attr_value) && (NULL != attr_name))
605   {
606     ret = 1;
607     fprintf (stderr, _ ("Attribute value missing!\n"));
608     return;
609   }
610
611   if ((NULL == rp) && (NULL != issue_attrs))
612   {
613     ret = 1;
614     fprintf (stderr, _ ("Requesting party key is required!\n"));
615     return;
616   }
617
618   reclaim_handle = GNUNET_RECLAIM_connect (c);
619   // Get Ego
620   identity_handle = GNUNET_IDENTITY_connect (c, &ego_cb, NULL);
621 }
622
623
624 int
625 main (int argc, char *const argv[])
626 {
627   exp_interval = GNUNET_TIME_UNIT_HOURS;
628   struct GNUNET_GETOPT_CommandLineOption options[] = {
629
630     GNUNET_GETOPT_option_string ('a',
631                                  "add",
632                                  "NAME",
633                                  gettext_noop ("Add an attribute NAME"),
634                                  &attr_name),
635     GNUNET_GETOPT_option_string ('d',
636                                  "delete",
637                                  "ID",
638                                  gettext_noop ("Delete the attribute with ID"),
639                                  &attr_delete),
640     GNUNET_GETOPT_option_string ('V',
641                                  "value",
642                                  "VALUE",
643                                  gettext_noop ("The attribute VALUE"),
644                                  &attr_value),
645     GNUNET_GETOPT_option_string ('e',
646                                  "ego",
647                                  "EGO",
648                                  gettext_noop ("The EGO to use"),
649                                  &ego_name),
650     GNUNET_GETOPT_option_string ('r',
651                                  "rp",
652                                  "RP",
653                                  gettext_noop (
654                                    "Specify the relying party for issue"),
655                                  &rp),
656     GNUNET_GETOPT_option_flag ('D',
657                                "dump",
658                                gettext_noop ("List attributes for EGO"),
659                                &list),
660     GNUNET_GETOPT_option_string (
661       'i',
662       "issue",
663       "A1,A2,...",
664       gettext_noop (
665         "Issue a ticket for a set of attributes separated by comma"),
666       &issue_attrs),
667     GNUNET_GETOPT_option_string ('C',
668                                  "consume",
669                                  "TICKET",
670                                  gettext_noop ("Consume a ticket"),
671                                  &consume_ticket),
672     GNUNET_GETOPT_option_string ('R',
673                                  "revoke",
674                                  "TICKET",
675                                  gettext_noop ("Revoke a ticket"),
676                                  &revoke_ticket),
677     GNUNET_GETOPT_option_string ('t',
678                                  "type",
679                                  "TYPE",
680                                  gettext_noop ("Type of attribute"),
681                                  &type_str),
682     GNUNET_GETOPT_option_flag ('T',
683                                "tickets",
684                                gettext_noop ("List tickets of ego"),
685                                &list_tickets),
686     GNUNET_GETOPT_option_relative_time ('E',
687                                         "expiration",
688                                         "INTERVAL",
689                                         gettext_noop (
690                                           "Expiration interval of the attribute"),
691                                         &exp_interval),
692
693     GNUNET_GETOPT_OPTION_END};
694   if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
695                                        argv,
696                                        "gnunet-reclaim",
697                                        _ ("re:claimID command line tool"),
698                                        options,
699                                        &run,
700                                        NULL))
701     return 1;
702   else
703     return ret;
704 }