uncrustify as demanded.
[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 }