global reindent, now with uncrustify hook enabled
[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
199   reclaim_op = NULL;
200   if (NULL != ticket)
201   {
202     ticket_str =
203       GNUNET_STRINGS_data_to_string_alloc (ticket,
204                                            sizeof(
205                                              struct GNUNET_RECLAIM_Ticket));
206     printf ("%s\n", ticket_str);
207     GNUNET_free (ticket_str);
208   }
209   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
210 }
211
212 static void
213 store_attr_cont (void *cls, int32_t success, const char *emsg)
214 {
215   reclaim_op = NULL;
216   if (GNUNET_SYSERR == success)
217   {
218     fprintf (stderr, "%s\n", emsg);
219   }
220   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
221 }
222
223 static void
224 process_attrs (void *cls,
225                const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
226                const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
227 {
228   char *value_str;
229   char *id;
230   const char *attr_type;
231
232   if (NULL == identity)
233   {
234     reclaim_op = NULL;
235     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
236     return;
237   }
238   if (NULL == attr)
239   {
240     ret = 1;
241     return;
242   }
243   value_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
244                                                         attr->data,
245                                                         attr->data_size);
246   attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
247   id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(uint64_t));
248   fprintf (stdout,
249            "Name: %s; Value: %s (%s); Version %u; ID: %s\n",
250            attr->name,
251            value_str,
252            attr_type,
253            attr->version,
254            id);
255   GNUNET_free (id);
256 }
257
258 static void
259 ticket_iter_err (void *cls)
260 {
261   ticket_iterator = NULL;
262   fprintf (stderr, "Failed to iterate over tickets\n");
263   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
264 }
265
266 static void
267 ticket_iter_fin (void *cls)
268 {
269   ticket_iterator = NULL;
270   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
271 }
272
273 static void
274 ticket_iter (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
275 {
276   char *aud;
277   char *ref;
278   char *tkt;
279
280   aud =
281     GNUNET_STRINGS_data_to_string_alloc (&ticket->audience,
282                                          sizeof(struct
283                                                 GNUNET_CRYPTO_EcdsaPublicKey));
284   ref = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof(uint64_t));
285   tkt =
286     GNUNET_STRINGS_data_to_string_alloc (ticket,
287                                          sizeof(struct GNUNET_RECLAIM_Ticket));
288   fprintf (stdout, "Ticket: %s | ID: %s | Audience: %s\n", tkt, ref, aud);
289   GNUNET_free (aud);
290   GNUNET_free (ref);
291   GNUNET_free (tkt);
292   GNUNET_RECLAIM_ticket_iteration_next (ticket_iterator);
293 }
294
295 static void
296 iter_error (void *cls)
297 {
298   attr_iterator = NULL;
299   fprintf (stderr, "Failed to iterate over attributes\n");
300   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
301 }
302
303 static void
304 timeout_task (void *cls)
305 {
306   timeout = NULL;
307   ret = 1;
308   fprintf (stderr, "Timeout\n");
309   if (NULL == cleanup_task)
310     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
311 }
312
313 static void
314 process_rvk (void *cls, int success, const char *msg)
315 {
316   reclaim_op = NULL;
317   if (GNUNET_OK != success)
318   {
319     fprintf (stderr, "Revocation failed.\n");
320     ret = 1;
321   }
322   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
323 }
324
325
326 static void
327 process_delete (void *cls, int success, const char *msg)
328 {
329   reclaim_op = NULL;
330   if (GNUNET_OK != success)
331   {
332     fprintf (stderr, "Deletion failed.\n");
333     ret = 1;
334   }
335   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
336 }
337
338
339 static void
340 iter_finished (void *cls)
341 {
342   char *data;
343   size_t data_size;
344   int type;
345
346   attr_iterator = NULL;
347   if (list)
348   {
349     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
350     return;
351   }
352
353   if (issue_attrs)
354   {
355     reclaim_op = GNUNET_RECLAIM_ticket_issue (reclaim_handle,
356                                               pkey,
357                                               &rp_key,
358                                               attr_list,
359                                               &ticket_issue_cb,
360                                               NULL);
361     return;
362   }
363   if (consume_ticket)
364   {
365     reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle,
366                                                 pkey,
367                                                 &ticket,
368                                                 &process_attrs,
369                                                 NULL);
370     timeout = GNUNET_SCHEDULER_add_delayed (
371       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
372       &timeout_task,
373       NULL);
374     return;
375   }
376   if (revoke_ticket)
377   {
378     reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle,
379                                                pkey,
380                                                &ticket,
381                                                &process_rvk,
382                                                NULL);
383     return;
384   }
385   if (attr_delete)
386   {
387     if (NULL == attr_to_delete)
388     {
389       fprintf (stdout, "No such attribute ``%s''\n", attr_delete);
390       return;
391     }
392     reclaim_op = GNUNET_RECLAIM_attribute_delete (reclaim_handle,
393                                                   pkey,
394                                                   attr_to_delete,
395                                                   &process_delete,
396                                                   NULL);
397     return;
398   }
399   if (attr_name)
400   {
401     if (NULL == type_str)
402       type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
403     else
404       type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str);
405
406     GNUNET_assert (GNUNET_SYSERR !=
407                    GNUNET_RECLAIM_ATTRIBUTE_string_to_value (type,
408                                                              attr_value,
409                                                              (void **) &data,
410                                                              &data_size));
411     if (NULL != claim)
412     {
413       claim->type = type;
414       claim->data = data;
415       claim->data_size = data_size;
416     }
417     else
418     {
419       claim =
420         GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr_name, type, data, data_size);
421     }
422     reclaim_op = GNUNET_RECLAIM_attribute_store (reclaim_handle,
423                                                  pkey,
424                                                  claim,
425                                                  &exp_interval,
426                                                  &store_attr_cont,
427                                                  NULL);
428     GNUNET_free (data);
429     GNUNET_free (claim);
430     return;
431   }
432   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
433 }
434
435 static void
436 iter_cb (void *cls,
437          const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
438          const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
439 {
440   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
441   char *attrs_tmp;
442   char *attr_str;
443   char *label;
444   char *id;
445   const char *attr_type;
446
447   if ((NULL != attr_name) && (NULL != claim))
448   {
449     if (0 == strcasecmp (attr_name, attr->name))
450     {
451       claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
452                                                   attr->type,
453                                                   attr->data,
454                                                   attr->data_size);
455     }
456   }
457   else if (issue_attrs)
458   {
459     attrs_tmp = GNUNET_strdup (issue_attrs);
460     attr_str = strtok (attrs_tmp, ",");
461     while (NULL != attr_str)
462     {
463       if (0 != strcasecmp (attr_str, attr->name))
464       {
465         attr_str = strtok (NULL, ",");
466         continue;
467       }
468       le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
469       le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
470                                                       attr->type,
471                                                       attr->data,
472                                                       attr->data_size);
473       le->claim->version = attr->version;
474       le->claim->id = attr->id;
475       GNUNET_CONTAINER_DLL_insert (attr_list->list_head,
476                                    attr_list->list_tail,
477                                    le);
478       break;
479     }
480     GNUNET_free (attrs_tmp);
481   }
482   else if (attr_delete && (NULL == attr_to_delete))
483   {
484     label = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(uint64_t));
485     if (0 == strcasecmp (attr_delete, label))
486     {
487       attr_to_delete = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name,
488                                                            attr->type,
489                                                            attr->data,
490                                                            attr->data_size);
491       attr_to_delete->id = attr->id;
492     }
493     GNUNET_free (label);
494   }
495   else if (list)
496   {
497     attr_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type,
498                                                          attr->data,
499                                                          attr->data_size);
500     attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
501     id = GNUNET_STRINGS_data_to_string_alloc (&attr->id, sizeof(uint64_t));
502     fprintf (stdout,
503              "Name: %s; Value: %s (%s); Version %u; ID: %s\n",
504              attr->name,
505              attr_str,
506              attr_type,
507              attr->version,
508              id);
509     GNUNET_free (id);
510   }
511   GNUNET_RECLAIM_get_attributes_next (attr_iterator);
512 }
513
514 static void
515 start_process ()
516 {
517   if (NULL == pkey)
518   {
519     fprintf (stderr, "Ego %s not found\n", ego_name);
520     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
521     return;
522   }
523
524   if (list_tickets)
525   {
526     ticket_iterator = GNUNET_RECLAIM_ticket_iteration_start (reclaim_handle,
527                                                              pkey,
528                                                              &ticket_iter_err,
529                                                              NULL,
530                                                              &ticket_iter,
531                                                              NULL,
532                                                              &ticket_iter_fin,
533                                                              NULL);
534     return;
535   }
536
537   if ((NULL != rp) &&
538       (GNUNET_OK !=
539        GNUNET_CRYPTO_ecdsa_public_key_from_string (rp, strlen (rp), &rp_key)) )
540   {
541     fprintf (stderr, "%s is not a public key!\n", rp);
542     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
543     return;
544   }
545   if (NULL != consume_ticket)
546     GNUNET_STRINGS_string_to_data (consume_ticket,
547                                    strlen (consume_ticket),
548                                    &ticket,
549                                    sizeof(struct GNUNET_RECLAIM_Ticket));
550   if (NULL != revoke_ticket)
551     GNUNET_STRINGS_string_to_data (revoke_ticket,
552                                    strlen (revoke_ticket),
553                                    &ticket,
554                                    sizeof(struct GNUNET_RECLAIM_Ticket));
555
556   attr_list = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
557   claim = NULL;
558   attr_iterator = GNUNET_RECLAIM_get_attributes_start (reclaim_handle,
559                                                        pkey,
560                                                        &iter_error,
561                                                        NULL,
562                                                        &iter_cb,
563                                                        NULL,
564                                                        &iter_finished,
565                                                        NULL);
566 }
567
568 static int init = GNUNET_YES;
569
570 static void
571 ego_cb (void *cls,
572         struct GNUNET_IDENTITY_Ego *ego,
573         void **ctx,
574         const char *name)
575 {
576   if (NULL == name)
577   {
578     if (GNUNET_YES == init)
579     {
580       init = GNUNET_NO;
581       start_process ();
582     }
583     return;
584   }
585   if (0 != strcmp (name, ego_name))
586     return;
587   pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
588 }
589
590
591 static void
592 run (void *cls,
593      char *const *args,
594      const char *cfgfile,
595      const struct GNUNET_CONFIGURATION_Handle *c)
596 {
597   ret = 0;
598   if (NULL == ego_name)
599   {
600     ret = 1;
601     fprintf (stderr, _ ("Ego is required\n"));
602     return;
603   }
604
605   if ((NULL == attr_value) && (NULL != attr_name))
606   {
607     ret = 1;
608     fprintf (stderr, _ ("Attribute value missing!\n"));
609     return;
610   }
611
612   if ((NULL == rp) && (NULL != issue_attrs))
613   {
614     ret = 1;
615     fprintf (stderr, _ ("Requesting party key is required!\n"));
616     return;
617   }
618
619   reclaim_handle = GNUNET_RECLAIM_connect (c);
620   // Get Ego
621   identity_handle = GNUNET_IDENTITY_connect (c, &ego_cb, NULL);
622 }
623
624
625 int
626 main (int argc, char *const argv[])
627 {
628   exp_interval = GNUNET_TIME_UNIT_HOURS;
629   struct GNUNET_GETOPT_CommandLineOption options[] = {
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   };
695   if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
696                                        argv,
697                                        "gnunet-reclaim",
698                                        _ ("re:claimID command line tool"),
699                                        options,
700                                        &run,
701                                        NULL))
702     return 1;
703   else
704     return ret;
705 }