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