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