RECLAIM: Simplify logic
[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 static void
161 do_cleanup (void *cls)
162 {
163   cleanup_task = NULL;
164   if (NULL != timeout)
165     GNUNET_SCHEDULER_cancel (timeout);
166   if (NULL != reclaim_op)
167     GNUNET_RECLAIM_cancel (reclaim_op);
168   if (NULL != attr_iterator)
169     GNUNET_RECLAIM_get_attributes_stop (attr_iterator);
170   if (NULL != ticket_iterator)
171     GNUNET_RECLAIM_ticket_iteration_stop (ticket_iterator);
172   if (NULL != reclaim_handle)
173     GNUNET_RECLAIM_disconnect (reclaim_handle);
174   if (NULL != identity_handle)
175     GNUNET_IDENTITY_disconnect (identity_handle);
176   if (NULL != abe_key)
177     GNUNET_free (abe_key);
178   if (NULL != attr_list)
179     GNUNET_free (attr_list);
180 }
181
182 static void
183 ticket_issue_cb (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
184 {
185   char *ticket_str;
186   reclaim_op = NULL;
187   if (NULL != ticket) {
188     ticket_str = GNUNET_STRINGS_data_to_string_alloc (
189         ticket, sizeof (struct GNUNET_RECLAIM_Ticket));
190     printf ("%s\n", ticket_str);
191     GNUNET_free (ticket_str);
192   }
193   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
194 }
195
196 static void
197 store_attr_cont (void *cls, int32_t success, const char *emsg)
198 {
199   reclaim_op = NULL;
200   if (GNUNET_SYSERR == success) {
201     fprintf (stderr, "%s\n", emsg);
202   }
203   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
204 }
205
206 static void
207 process_attrs (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
208                const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
209 {
210   char *value_str;
211   const char *attr_type;
212
213   if (NULL == identity) {
214     reclaim_op = NULL;
215     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
216     return;
217   }
218   if (NULL == attr) {
219     ret = 1;
220     return;
221   }
222   value_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, attr->data,
223                                                         attr->data_size);
224   attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
225   fprintf (stdout, "%s: %s [%s,v%u,id=%" PRIu64 "]\n", attr->name, value_str,
226            attr_type, attr->version, attr->id);
227 }
228
229 static void
230 ticket_iter_err (void *cls)
231 {
232   ticket_iterator = NULL;
233   fprintf (stderr, "Failed to iterate over tickets\n");
234   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
235 }
236
237 static void
238 ticket_iter_fin (void *cls)
239 {
240   ticket_iterator = NULL;
241   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
242 }
243
244 static void
245 ticket_iter (void *cls, const struct GNUNET_RECLAIM_Ticket *ticket)
246 {
247   char *aud;
248   char *ref;
249
250   aud = GNUNET_STRINGS_data_to_string_alloc (
251       &ticket->audience, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
252   ref = GNUNET_STRINGS_data_to_string_alloc (&ticket->rnd, sizeof (uint64_t));
253
254   fprintf (stdout, "Ticket ID: %s | Audience: %s\n", ref, aud);
255   GNUNET_RECLAIM_ticket_iteration_next (ticket_iterator);
256 }
257
258 static void
259 iter_error (void *cls)
260 {
261   attr_iterator = NULL;
262   fprintf (stderr, "Failed to iterate over attributes\n");
263   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
264 }
265
266 static void
267 timeout_task (void *cls)
268 {
269   timeout = NULL;
270   ret = 1;
271   fprintf (stderr, "Timeout\n");
272   if (NULL == cleanup_task)
273     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
274 }
275
276 static void
277 process_rvk (void *cls, int success, const char *msg)
278 {
279   reclaim_op = NULL;
280   if (GNUNET_OK != success) {
281     fprintf (stderr, "Revocation failed.\n");
282     ret = 1;
283   }
284   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
285 }
286
287 static void
288 iter_finished (void *cls)
289 {
290   char *data;
291   size_t data_size;
292   int type;
293
294   attr_iterator = NULL;
295   if (list) {
296     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
297     return;
298   }
299
300   if (issue_attrs) {
301     reclaim_op = GNUNET_RECLAIM_ticket_issue (
302         reclaim_handle, pkey, &rp_key, attr_list, &ticket_issue_cb, NULL);
303     return;
304   }
305   if (consume_ticket) {
306     reclaim_op = GNUNET_RECLAIM_ticket_consume (reclaim_handle, pkey, &ticket,
307                                                 &process_attrs, NULL);
308     timeout = GNUNET_SCHEDULER_add_delayed (
309         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10),
310         &timeout_task, NULL);
311     return;
312   }
313   if (revoke_ticket) {
314     reclaim_op = GNUNET_RECLAIM_ticket_revoke (reclaim_handle, pkey, &ticket,
315                                                &process_rvk, NULL);
316     return;
317   }
318   if (attr_name) {
319     if (NULL == type_str)
320       type = GNUNET_RECLAIM_ATTRIBUTE_TYPE_STRING;
321     else
322       type = GNUNET_RECLAIM_ATTRIBUTE_typename_to_number (type_str);
323
324     GNUNET_assert (GNUNET_SYSERR !=
325                    GNUNET_RECLAIM_ATTRIBUTE_string_to_value (
326                        type, attr_value, (void **)&data, &data_size));
327     if (NULL != claim) {
328       claim->type = type;
329       claim->data = data;
330       claim->data_size = data_size;
331     } else {
332       claim =
333           GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr_name, type, data, data_size);
334     }
335     reclaim_op = GNUNET_RECLAIM_attribute_store (
336         reclaim_handle, pkey, claim, &exp_interval, &store_attr_cont, NULL);
337     GNUNET_free (data);
338     GNUNET_free (claim);
339     return;
340   }
341   cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
342 }
343
344 static void
345 iter_cb (void *cls, const struct GNUNET_CRYPTO_EcdsaPublicKey *identity,
346          const struct GNUNET_RECLAIM_ATTRIBUTE_Claim *attr)
347 {
348   struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry *le;
349   char *attrs_tmp;
350   char *attr_str;
351   const char *attr_type;
352
353   if ((NULL != attr_name) && (NULL != claim)) {
354     if (0 == strcasecmp (attr_name, attr->name)) {
355       claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (attr->name, attr->type,
356                                                   attr->data, attr->data_size);
357     }
358   } else if (issue_attrs) {
359     attrs_tmp = GNUNET_strdup (issue_attrs);
360     attr_str = strtok (attrs_tmp, ",");
361     while (NULL != attr_str) {
362       if (0 != strcasecmp (attr_str, attr->name)) {
363         attr_str = strtok (NULL, ",");
364         continue;
365       }
366       le = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimListEntry);
367       le->claim = GNUNET_RECLAIM_ATTRIBUTE_claim_new (
368           attr->name, attr->type, attr->data, attr->data_size);
369       le->claim->version = attr->version;
370       le->claim->id = attr->id;
371       GNUNET_CONTAINER_DLL_insert (attr_list->list_head, attr_list->list_tail,
372                                    le);
373       break;
374     }
375     GNUNET_free (attrs_tmp);
376   } else if (list) {
377     attr_str = GNUNET_RECLAIM_ATTRIBUTE_value_to_string (attr->type, attr->data,
378                                                          attr->data_size);
379     attr_type = GNUNET_RECLAIM_ATTRIBUTE_number_to_typename (attr->type);
380     fprintf (stdout, "%s: %s [%s,v%u,id=%" PRIu64 "]\n", attr->name, attr_str,
381              attr_type, attr->version, attr->id);
382   }
383   GNUNET_RECLAIM_get_attributes_next (attr_iterator);
384 }
385
386 static void
387 start_process ()
388 {
389   if (NULL == pkey) {
390     fprintf (stderr, "Ego %s not found\n", ego_name);
391     cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup, NULL);
392     return;
393   }
394
395   if (list_tickets) {
396     ticket_iterator = GNUNET_RECLAIM_ticket_iteration_start (
397         reclaim_handle, pkey, &ticket_iter_err, NULL, &ticket_iter, NULL,
398         &ticket_iter_fin, NULL);
399     return;
400   }
401
402   if (NULL != rp)
403     GNUNET_CRYPTO_ecdsa_public_key_from_string (rp, strlen (rp), &rp_key);
404   if (NULL != consume_ticket)
405     GNUNET_STRINGS_string_to_data (consume_ticket, strlen (consume_ticket),
406                                    &ticket,
407                                    sizeof (struct GNUNET_RECLAIM_Ticket));
408   if (NULL != revoke_ticket)
409     GNUNET_STRINGS_string_to_data (revoke_ticket, strlen (revoke_ticket),
410                                    &ticket,
411                                    sizeof (struct GNUNET_RECLAIM_Ticket));
412
413   attr_list = GNUNET_new (struct GNUNET_RECLAIM_ATTRIBUTE_ClaimList);
414   claim = NULL;
415   attr_iterator = GNUNET_RECLAIM_get_attributes_start (
416       reclaim_handle, pkey, &iter_error, NULL, &iter_cb, NULL, &iter_finished,
417       NULL);
418 }
419
420 static int init = GNUNET_YES;
421
422 static void
423 ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx,
424         const char *name)
425 {
426   if (NULL == name) {
427     if (GNUNET_YES == init) {
428       init = GNUNET_NO;
429       start_process ();
430     }
431     return;
432   }
433   if (0 != strcmp (name, ego_name))
434     return;
435   pkey = GNUNET_IDENTITY_ego_get_private_key (ego);
436 }
437
438
439 static void
440 run (void *cls, char *const *args, const char *cfgfile,
441      const struct GNUNET_CONFIGURATION_Handle *c)
442 {
443   ret = 0;
444   if (NULL == ego_name) {
445     ret = 1;
446     fprintf (stderr, _ ("Ego is required\n"));
447     return;
448   }
449
450   if ((NULL == attr_value) && (NULL != attr_name)) {
451     ret = 1;
452     fprintf (stderr, _ ("Attribute value missing!\n"));
453     return;
454   }
455
456   if ((NULL == rp) && (NULL != issue_attrs)) {
457     ret = 1;
458     fprintf (stderr, _ ("Requesting party key is required!\n"));
459     return;
460   }
461
462   reclaim_handle = GNUNET_RECLAIM_connect (c);
463   // Get Ego
464   identity_handle = GNUNET_IDENTITY_connect (c, &ego_cb, NULL);
465 }
466
467
468 int
469 main (int argc, char *const argv[])
470 {
471   exp_interval = GNUNET_TIME_UNIT_HOURS;
472   struct GNUNET_GETOPT_CommandLineOption options[] = {
473
474       GNUNET_GETOPT_option_string ('a', "add", "NAME",
475                                    gettext_noop ("Add an attribute NAME"),
476                                    &attr_name),
477
478       GNUNET_GETOPT_option_string ('V', "value", "VALUE",
479                                    gettext_noop ("The attribute VALUE"),
480                                    &attr_value),
481       GNUNET_GETOPT_option_string ('e', "ego", "EGO",
482                                    gettext_noop ("The EGO to use"), &ego_name),
483       GNUNET_GETOPT_option_string (
484           'r', "rp", "RP", gettext_noop ("Specify the relying party for issue"),
485           &rp),
486       GNUNET_GETOPT_option_flag (
487           'D', "dump", gettext_noop ("List attributes for EGO"), &list),
488       GNUNET_GETOPT_option_string (
489           'i', "issue", "A1,A2,...",
490           gettext_noop (
491               "Issue a ticket for a set of attributes separated by comma"),
492           &issue_attrs),
493       GNUNET_GETOPT_option_string ('C', "consume", "TICKET",
494                                    gettext_noop ("Consume a ticket"),
495                                    &consume_ticket),
496       GNUNET_GETOPT_option_string ('R', "revoke", "TICKET",
497                                    gettext_noop ("Revoke a ticket"),
498                                    &revoke_ticket),
499       GNUNET_GETOPT_option_string (
500           't', "type", "TYPE", gettext_noop ("Type of attribute"), &type_str),
501       GNUNET_GETOPT_option_flag (
502           'T', "tickets", gettext_noop ("List tickets of ego"), &list_tickets),
503       GNUNET_GETOPT_option_relative_time (
504           'E', "expiration", "INTERVAL",
505           gettext_noop ("Expiration interval of the attribute"), &exp_interval),
506
507       GNUNET_GETOPT_OPTION_END};
508   if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "gnunet-reclaim",
509                                        _ ("re:claimID command line tool"),
510                                        options, &run, NULL))
511     return 1;
512   else
513     return ret;
514 }