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