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