-remove debug message
[oweals/gnunet.git] / src / identity / gnunet-identity.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2018, 2019 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  * @file identity/gnunet-identity.c
22  * @brief IDENTITY management command line tool
23  * @author Christian Grothoff
24  *
25  * Todo:
26  * - add options to get default egos
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_identity_service.h"
31
32
33 /**
34  * Return value from main on timeout.
35  */
36 #define TIMEOUT_STATUS_CODE 40
37
38 /**
39  * Handle to IDENTITY service.
40  */
41 static struct GNUNET_IDENTITY_Handle *sh;
42
43 /**
44  * Was "list" specified?
45  */
46 static int list;
47
48 /**
49  * Was "monitor" specified?
50  */
51 static int monitor;
52
53 /**
54  * Was "private" specified?
55  */
56 static int private_keys;
57
58 /**
59  * Was "verbose" specified?
60  */
61 static unsigned int verbose;
62
63 /**
64  * Was "quiet" specified?
65  */
66 static int quiet;
67
68 /**
69  * -C option
70  */
71 static char *create_ego;
72
73 /**
74  * -D option
75  */
76 static char *delete_ego;
77
78 /**
79  * -P option
80  */
81 static char *privkey_ego;
82
83 /**
84  * -s option.
85  */
86 static char *set_ego;
87
88 /**
89  * -S option.
90  */
91 static char *set_subsystem;
92
93 /**
94  * Operation handle for set operation.
95  */
96 static struct GNUNET_IDENTITY_Operation *set_op;
97
98 /**
99  * Handle for create operation.
100  */
101 static struct GNUNET_IDENTITY_Operation *create_op;
102
103 /**
104  * Handle for delete operation.
105  */
106 static struct GNUNET_IDENTITY_Operation *delete_op;
107
108 /**
109  * Private key from command line option, or NULL.
110  */
111 struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
112
113 /**
114  * Value to return from #main().
115  */
116 static int global_ret;
117
118
119 /**
120  * Task run on shutdown.
121  *
122  * @param cls NULL
123  */
124 static void
125 shutdown_task (void *cls)
126 {
127   if (NULL != set_op)
128   {
129     GNUNET_IDENTITY_cancel (set_op);
130     set_op = NULL;
131   }
132   if (NULL != create_op)
133   {
134     GNUNET_IDENTITY_cancel (create_op);
135     create_op = NULL;
136   }
137   if (NULL != delete_op)
138   {
139     GNUNET_IDENTITY_cancel (delete_op);
140     delete_op = NULL;
141   }
142   if (NULL != set_ego)
143   {
144     GNUNET_free (set_ego);
145     set_ego = NULL;
146   }
147   GNUNET_IDENTITY_disconnect (sh);
148   sh = NULL;
149 }
150
151
152 /**
153  * Test if we are finished yet.
154  */
155 static void
156 test_finished (void)
157 {
158   if ( (NULL == create_op) &&
159        (NULL == delete_op) &&
160        (NULL == set_op) &&
161        (NULL == set_subsystem) &&
162        (! list) &&
163        (! monitor))
164   {
165     if (TIMEOUT_STATUS_CODE == global_ret)
166       global_ret = 0;
167     GNUNET_SCHEDULER_shutdown ();
168   }
169 }
170
171
172 /**
173  * Deletion operation finished.
174  *
175  * @param cls pointer to operation handle
176  * @param emsg NULL on success, otherwise an error message
177  */
178 static void
179 delete_finished (void *cls,
180                  const char *emsg)
181 {
182   struct GNUNET_IDENTITY_Operation **op = cls;
183
184   *op = NULL;
185   if (NULL != emsg)
186     fprintf (stderr, "%s\n", gettext (emsg));
187   test_finished ();
188 }
189
190
191 /**
192  * Creation operation finished.
193  *
194  * @param cls pointer to operation handle
195  * @param pk private key of the ego, or NULL on error
196  * @param emsg error message, NULL on success
197  */
198 static void
199 create_finished (void *cls,
200                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
201                  const char *emsg)
202 {
203   struct GNUNET_IDENTITY_Operation **op = cls;
204
205   *op = NULL;
206   if (NULL == pk)
207   {
208     fprintf (stderr,
209              _ ("Failed to create ego: %s\n"),
210              emsg);
211     global_ret = 1;
212   }
213   else if (verbose)
214   {
215     struct GNUNET_CRYPTO_EcdsaPublicKey pub;
216     char *pubs;
217
218     GNUNET_CRYPTO_ecdsa_key_get_public (pk, &pub);
219     pubs = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pub);
220     if (private_keys)
221     {
222       char *privs;
223
224       privs = GNUNET_CRYPTO_ecdsa_private_key_to_string (pk);
225       fprintf (stdout, "%s - %s\n", pubs, privs);
226       GNUNET_free (privs);
227     }
228     else
229     {
230       fprintf (stdout, "%s\n", pubs);
231     }
232     GNUNET_free (pubs);
233   }
234   test_finished ();
235 }
236
237
238 /**
239  * Function called by #GNUNET_IDENTITY_set up on completion.
240  *
241  * @param cls NULL
242  * @param emsg error message (NULL on success)
243  */
244 static void
245 set_done (void *cls, const char *emsg)
246 {
247   set_op = NULL;
248   if (NULL != emsg)
249   {
250     fprintf (stderr, _ ("Failed to set default ego: %s\n"), emsg);
251     global_ret = 1;
252   }
253   test_finished ();
254 }
255
256
257 /**
258  * If listing is enabled, prints information about the egos.
259  *
260  * This function is initially called for all egos and then again
261  * whenever a ego's identifier changes or if it is deleted.  At the
262  * end of the initial pass over all egos, the function is once called
263  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
264  * be invoked in the future or that there was an error.
265  *
266  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
267  * this function is only called ONCE, and 'NULL' being passed in
268  * 'ego' does indicate an error (i.e. name is taken or no default
269  * value is known).  If 'ego' is non-NULL and if '*ctx'
270  * is set in those callbacks, the value WILL be passed to a subsequent
271  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
272  * that one was not NULL).
273  *
274  * When an identity is renamed, this function is called with the
275  * (known) ego but the NEW identifier.
276  *
277  * When an identity is deleted, this function is called with the
278  * (known) ego and "NULL" for the 'identifier'.  In this case,
279  * the 'ego' is henceforth invalid (and the 'ctx' should also be
280  * cleaned up).
281  *
282  * @param cls closure
283  * @param ego ego handle
284  * @param ctx context for application to store data for this ego
285  *                 (during the lifetime of this process, initially NULL)
286  * @param identifier identifier assigned by the user for this ego,
287  *                   NULL if the user just deleted the ego and it
288  *                   must thus no longer be used
289  */
290 static void
291 print_ego (void *cls,
292            struct GNUNET_IDENTITY_Ego *ego,
293            void **ctx,
294            const char *identifier)
295 {
296   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
297   char *s;
298   char *privs;
299
300   if ( (NULL != set_ego) &&
301        (NULL != set_subsystem) &&
302        (NULL != ego) &&
303        (NULL != identifier) &&
304        (0 == strcmp (identifier, set_ego)))
305   {
306     set_op = GNUNET_IDENTITY_set (sh,
307                                   set_subsystem,
308                                   ego,
309                                   &set_done,
310                                   NULL);
311     GNUNET_free (set_subsystem);
312     set_subsystem = NULL;
313     GNUNET_free (set_ego);
314     set_ego = NULL;
315   }
316   if ( (NULL == ego) &&
317        (NULL != set_ego) &&
318        (NULL != set_subsystem) )
319   {
320     fprintf (stderr,
321              "Could not set ego to `%s' for subsystem `%s', ego not known\n",
322              set_ego,
323              set_subsystem);
324     GNUNET_free (set_subsystem);
325     set_subsystem = NULL;
326     GNUNET_free (set_ego);
327     set_ego = NULL;
328   }
329   if ((NULL == ego) && (! monitor))
330   {
331     list = 0;
332     test_finished ();
333     return;
334   }
335   if (! (list | monitor))
336     return;
337   if ( (NULL == ego) ||
338        (NULL == identifier) )
339     return;
340   if ( (NULL != set_ego) &&
341        (0 != strcmp (identifier,
342                      set_ego)) )
343     return;
344   GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
345   s = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
346   privs = GNUNET_CRYPTO_ecdsa_private_key_to_string (
347     GNUNET_IDENTITY_ego_get_private_key (ego));
348   if ((monitor) || (NULL != identifier))
349   {
350     if (quiet)
351     {
352       if (private_keys)
353         fprintf (stdout, "%s - %s\n", s, privs);
354       else
355         fprintf (stdout, "%s\n", s);
356     }
357     else
358     {
359       if (private_keys)
360         fprintf (stdout, "%s - %s - %s\n", identifier, s, privs);
361       else
362         fprintf (stdout, "%s - %s\n", identifier, s);
363     }
364   }
365   GNUNET_free (privs);
366   GNUNET_free (s);
367 }
368
369
370 /**
371  * Main function that will be run by the scheduler.
372  *
373  * @param cls closure
374  * @param args remaining command-line arguments
375  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
376  * @param cfg configuration
377  */
378 static void
379 run (void *cls,
380      char *const *args,
381      const char *cfgfile,
382      const struct GNUNET_CONFIGURATION_Handle *cfg)
383 {
384   if ((NULL != set_subsystem) && (NULL == set_ego))
385   {
386     fprintf (stderr, "Option -s requires option -e to be specified as well.\n");
387     return;
388   }
389   sh = GNUNET_IDENTITY_connect (cfg,
390                                 (monitor | list) ||
391                                 (NULL != set_ego) ||
392                                 (NULL != set_subsystem)
393                                 ? &print_ego
394                                 : NULL,
395                                 NULL);
396   if (NULL != delete_ego)
397     delete_op =
398       GNUNET_IDENTITY_delete (sh,
399                               delete_ego,
400                               &delete_finished,
401                               &delete_op);
402   if (NULL != create_ego)
403   {
404     if (NULL != privkey_ego)
405     {
406       GNUNET_STRINGS_string_to_data (privkey_ego,
407                                      strlen (privkey_ego),
408                                      &pk,
409                                      sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey));
410       create_op =
411         GNUNET_IDENTITY_create (sh,
412                                 create_ego,
413                                 &pk,
414                                 &create_finished,
415                                 &create_op);
416     }
417     else
418       create_op =
419         GNUNET_IDENTITY_create (sh,
420                                 create_ego,
421                                 NULL,
422                                 &create_finished,
423                                 &create_op);
424   }
425   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
426                                  NULL);
427   test_finished ();
428 }
429
430
431 /**
432  * The main function.
433  *
434  * @param argc number of arguments from the command line
435  * @param argv command line arguments
436  * @return 0 ok, 1 on error
437  */
438 int
439 main (int argc, char *const *argv)
440 {
441   struct GNUNET_GETOPT_CommandLineOption options[] = {
442     GNUNET_GETOPT_option_string ('C',
443                                  "create",
444                                  "NAME",
445                                  gettext_noop ("create ego NAME"),
446                                  &create_ego),
447     GNUNET_GETOPT_option_string ('D',
448                                  "delete",
449                                  "NAME",
450                                  gettext_noop ("delete ego NAME "),
451                                  &delete_ego),
452     GNUNET_GETOPT_option_string ('P',
453                                  "privkey",
454                                  "PRIVATE_KEY",
455                                  gettext_noop ("set the private key for the identity to PRIVATE_KEY (use together with -C)"),
456                                  &privkey_ego),
457     GNUNET_GETOPT_option_flag ('d',
458                                "display",
459                                gettext_noop ("display all egos"),
460                                &list),
461     GNUNET_GETOPT_option_flag ('q',
462                                "quiet",
463                                gettext_noop ("reduce output"),
464                                &quiet),
465     GNUNET_GETOPT_option_string (
466       'e',
467       "ego",
468       "NAME",
469       gettext_noop (
470         "set default identity to NAME for a subsystem SUBSYSTEM (use together with -s) or restrict results to NAME (use together with -d)"),
471       &set_ego),
472     GNUNET_GETOPT_option_flag ('m',
473                                "monitor",
474                                gettext_noop ("run in monitor mode egos"),
475                                &monitor),
476     GNUNET_GETOPT_option_flag ('p',
477                                "private-keys",
478                                gettext_noop ("display private keys as well"),
479                                &private_keys),
480     GNUNET_GETOPT_option_string (
481       's',
482       "set",
483       "SUBSYSTEM",
484       gettext_noop (
485         "set default identity to EGO for a subsystem SUBSYSTEM (use together with -e)"),
486       &set_subsystem),
487     GNUNET_GETOPT_option_verbose (&verbose),
488     GNUNET_GETOPT_OPTION_END
489   };
490   int res;
491
492   if (GNUNET_OK !=
493       GNUNET_STRINGS_get_utf8_args (argc, argv,
494                                     &argc, &argv))
495     return 4;
496   global_ret = TIMEOUT_STATUS_CODE; /* timeout */
497   res = GNUNET_PROGRAM_run (argc,
498                             argv,
499                             "gnunet-identity",
500                             gettext_noop ("Maintain egos"),
501                             options,
502                             &run,
503                             NULL);
504   GNUNET_free_nz ((void *) argv);
505
506   if (GNUNET_OK != res)
507     return 3;
508   return global_ret;
509 }
510
511
512 /* end of gnunet-identity.c */