uncrustify as demanded.
[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 /* end of gnunet-identity.c */