splitting 'struct GNUNET_CRYPTO_EccPublicKey' into one struct for signing and another...
[oweals/gnunet.git] / src / gns / gnunet-gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012-2013 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file gnunet-gns.c
22  * @brief command line tool to access distributed GNS
23  * @author Christian Grothoff
24  */
25 #include "platform.h"
26 #include <gnunet_util_lib.h>
27 #include <gnunet_dnsparser_lib.h>
28 #include <gnunet_identity_service.h>
29 #include <gnunet_namestore_service.h>
30 #include <gnunet_gns_service.h>
31
32 /**
33  * Configuration we are using.
34  */
35 static const struct GNUNET_CONFIGURATION_Handle *cfg;
36
37 /**
38  * Handle to GNS service.
39  */
40 static struct GNUNET_GNS_Handle *gns;
41
42 /**
43  * GNS name to lookup. (-u option)
44  */
45 static char *lookup_name;
46
47 /**
48  * record type to look up (-t option)
49  */
50 static char *lookup_type;
51
52 /**
53  * Identity of the zone to use for the lookup (-z option)
54  */
55 static char *zone_ego_name;
56
57 /**
58  * Public key of the zone to use for the lookup (-p option)
59  */
60 static char *public_key;
61
62 /**
63  * raw output
64  */
65 static int raw;
66
67 /**
68  * Requested record type.
69  */
70 static int rtype;
71
72 /**
73  * Handle to lookup request 
74  */
75 static struct GNUNET_GNS_LookupRequest *lookup_request;
76
77 /**
78  * Lookup an ego with the identity service.
79  */
80 static struct GNUNET_IDENTITY_EgoLookup *el;
81
82 /**
83  * Handle for identity service.
84  */
85 static struct GNUNET_IDENTITY_Handle *identity;
86
87 /**
88  * Active operation on identity service.
89  */
90 static struct GNUNET_IDENTITY_Operation *id_op;
91
92
93 /**
94  * Task run on shutdown.  Cleans up everything.
95  *
96  * @param cls unused
97  * @param tc scheduler context
98  */
99 static void
100 do_shutdown (void *cls,
101              const struct GNUNET_SCHEDULER_TaskContext *tc)
102 {
103   if (NULL != el)
104   {
105     GNUNET_IDENTITY_ego_lookup_cancel (el);
106     el = NULL;
107   }
108   if (NULL != id_op)
109   {
110     GNUNET_IDENTITY_cancel (id_op);
111     id_op = NULL;
112   }
113   if (NULL != lookup_request)
114   {
115     GNUNET_GNS_lookup_cancel (lookup_request);
116     lookup_request = NULL;
117   }
118   if (NULL != identity)
119   {
120     GNUNET_IDENTITY_disconnect (identity);
121     identity = NULL;
122   }
123   if (NULL != gns)
124   {
125     GNUNET_GNS_disconnect (gns);
126     gns = NULL;
127   }
128 }
129
130
131 /**
132  * Function called with the result of a GADS lookup.
133  *
134  * @param cls the 'const char *' name that was resolved
135  * @param rd_count number of records returned
136  * @param rd array of 'rd_count' records with the results
137  */
138 static void
139 process_lookup_result (void *cls, uint32_t rd_count,
140                        const struct GNUNET_NAMESTORE_RecordData *rd)
141 {
142   const char *name = cls;
143   uint32_t i;
144   const char *typename;
145   char* string_val;
146
147   lookup_request = NULL; 
148   if (!raw) 
149   {
150     if (0 == rd_count)
151       printf ("No results.\n");
152     else
153       printf ("%s:\n", 
154               name);
155   }
156   for (i=0; i<rd_count; i++)
157   {
158     typename = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
159     string_val = GNUNET_NAMESTORE_value_to_string (rd[i].record_type,
160                                                    rd[i].data,
161                                                    rd[i].data_size);
162     if (raw)
163       printf ("%s\n", 
164               string_val);
165     else
166       printf ("Got `%s' record: %s\n",
167               typename, 
168               string_val);
169     GNUNET_free_non_null (string_val);
170   }
171   GNUNET_SCHEDULER_shutdown ();
172 }
173
174
175 /**
176  * Perform the actual resolution, starting with the zone
177  * identified by the given public key and the shorten zone.
178  *
179  * @param pkey public key to use for the zone, can be NULL
180  * @param shorten_key private key used for shortening, can be NULL
181  */
182 static void
183 lookup_with_keys (const struct GNUNET_CRYPTO_EccPublicSignKey *pkey,
184                   const struct GNUNET_CRYPTO_EccPrivateKey *shorten_key)
185 {
186   if (NULL != lookup_type)
187     rtype = GNUNET_NAMESTORE_typename_to_number (lookup_type);
188   else
189     rtype = GNUNET_DNSPARSER_TYPE_A;
190
191   if (NULL != lookup_name)
192   {
193     lookup_request = GNUNET_GNS_lookup (gns, 
194                                         lookup_name,
195                                         pkey,
196                                         rtype,
197                                         GNUNET_NO, /* Use DHT */
198                                         shorten_key,
199                                         &process_lookup_result, 
200                                         lookup_name);
201   }
202   else
203   {
204     fprintf (stderr,
205              _("Please specify name to lookup!\n"));
206     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
207     return;
208   }
209 }
210
211
212 /** 
213  * Method called to with the ego we are to use for shortening
214  * during the lookup.
215  *
216  * @param cls closure contains the public key to use
217  * @param ego ego handle, NULL if not found
218  * @param ctx context for application to store data for this ego
219  *                 (during the lifetime of this process, initially NULL)
220  * @param name name assigned by the user for this ego,
221  *                   NULL if the user just deleted the ego and it
222  *                   must thus no longer be used
223  */
224 static void 
225 identity_shorten_cb (void *cls,
226                      struct GNUNET_IDENTITY_Ego *ego,
227                      void **ctx,
228                      const char *name)
229 {
230   struct GNUNET_CRYPTO_EccPublicSignKey *pkeym = cls;
231
232   id_op = NULL;
233   if (NULL == ego) 
234     lookup_with_keys (pkeym, NULL);
235   else
236     lookup_with_keys (pkeym,
237                       GNUNET_IDENTITY_ego_get_private_key (ego));
238   GNUNET_free (pkeym);
239 }
240
241
242 /**
243  * Perform the actual resolution, starting with the zone
244  * identified by the given public key.
245  *
246  * @param pkey public key to use for the zone
247  */
248 static void
249 lookup_with_public_key (const struct GNUNET_CRYPTO_EccPublicSignKey *pkey)
250 {
251   struct GNUNET_CRYPTO_EccPublicSignKey *pkeym;
252
253   GNUNET_assert (NULL != pkey);
254   pkeym = GNUNET_new (struct GNUNET_CRYPTO_EccPublicSignKey);
255   *pkeym = *pkey;
256   id_op = GNUNET_IDENTITY_get (identity,
257                                "shorten-zone",
258                                &identity_shorten_cb,
259                                pkeym);
260   if (NULL == id_op)
261   {
262     GNUNET_break (0);
263     lookup_with_keys (pkey, NULL);
264   }
265 }
266
267
268 /** 
269  * Method called to with the ego we are to use for the lookup,
270  * when the ego is determined by a name.
271  *
272  * @param cls closure (NULL, unused)
273  * @param ego ego handle, NULL if not found
274  */
275 static void 
276 identity_zone_cb (void *cls,
277                   const struct GNUNET_IDENTITY_Ego *ego)
278 {
279   struct GNUNET_CRYPTO_EccPublicSignKey pkey;
280
281   el = NULL;
282   if (NULL == ego) 
283   {
284     fprintf (stderr,
285              _("Ego for `%s' not found, cannot perform lookup.\n"),
286              zone_ego_name);
287     GNUNET_SCHEDULER_shutdown ();
288   }
289   else
290   {
291     GNUNET_IDENTITY_ego_get_public_key (ego, &pkey);
292     lookup_with_public_key (&pkey);
293   }
294   GNUNET_free_non_null (zone_ego_name);
295   zone_ego_name = NULL;
296 }
297
298
299 /** 
300  * Method called to with the ego we are to use for the lookup,
301  * when the ego is the one for the default master zone.
302  *
303  * @param cls closure (NULL, unused)
304  * @param ego ego handle, NULL if not found
305  * @param ctx context for application to store data for this ego
306  *                 (during the lifetime of this process, initially NULL)
307  * @param name name assigned by the user for this ego,
308  *                   NULL if the user just deleted the ego and it
309  *                   must thus no longer be used
310  */
311 static void 
312 identity_master_cb (void *cls,
313                     struct GNUNET_IDENTITY_Ego *ego,
314                     void **ctx,
315                     const char *name)
316 {
317   struct GNUNET_CRYPTO_EccPublicSignKey pkey;
318
319   id_op = NULL;
320   if (NULL == ego) 
321   {
322     fprintf (stderr,
323              _("Ego for `master-zone' not found, cannot perform lookup.  Did you run gnunet-gns-import.sh?\n"));
324     GNUNET_SCHEDULER_shutdown ();
325     return;
326   }
327   GNUNET_IDENTITY_ego_get_public_key (ego, &pkey);
328   lookup_with_public_key (&pkey);
329 }
330
331
332 /**
333  * Main function that will be run.
334  *
335  * @param cls closure
336  * @param args remaining command-line arguments
337  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
338  * @param c configuration
339  */
340 static void
341 run (void *cls, char *const *args, const char *cfgfile,
342      const struct GNUNET_CONFIGURATION_Handle *c)
343 {
344   struct GNUNET_CRYPTO_EccPublicSignKey pkey;
345
346   cfg = c;
347   gns = GNUNET_GNS_connect (cfg);
348   identity = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
349   if (NULL == gns)
350   {
351     fprintf (stderr,
352              _("Failed to connect to GNS\n"));
353     return;
354   }
355   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
356                                 &do_shutdown, NULL);
357   if (NULL != public_key)
358   {
359     if (GNUNET_OK !=
360         GNUNET_CRYPTO_ecc_public_sign_key_from_string (public_key,
361                                                   strlen (public_key),
362                                                   &pkey))
363     {
364       fprintf (stderr, 
365                _("Public key `%s' is not well-formed\n"),
366                public_key);
367       GNUNET_SCHEDULER_shutdown ();
368       return;
369     }
370     lookup_with_public_key (&pkey);
371     return;
372   }
373   if (NULL != zone_ego_name)
374   {
375     el = GNUNET_IDENTITY_ego_lookup (cfg, 
376                                      zone_ego_name,
377                                      &identity_zone_cb,
378                                      NULL);
379     return;
380   }
381   if ( (NULL != lookup_name) &&
382        (strlen (lookup_name) > 4) &&
383        (0 == strcmp (".zkey",
384                      &lookup_name[strlen (lookup_name) - 4])) )
385   {
386     /* no zone required, use 'anonymous' zone */
387     GNUNET_CRYPTO_ecc_key_get_public_for_signature (GNUNET_CRYPTO_ecc_key_get_anonymous (),
388                                       &pkey);
389     lookup_with_public_key (&pkey);
390   }
391   else
392   {
393     id_op = GNUNET_IDENTITY_get (identity,
394                                  "master-zone",
395                                  &identity_master_cb,
396                                  NULL);
397     GNUNET_assert (NULL != id_op);
398   }
399 }
400
401
402 /**
403  * The main function for gnunet-gns.
404  *
405  * @param argc number of arguments from the command line
406  * @param argv command line arguments
407  * @return 0 ok, 1 on error
408  */
409 int
410 main (int argc, char *const *argv)
411 {
412   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
413     {'u', "lookup", "NAME",
414       gettext_noop ("Lookup a record for the given name"), 1,
415       &GNUNET_GETOPT_set_string, &lookup_name},
416     {'t', "type", "TYPE",
417       gettext_noop ("Specify the type of the record to lookup"), 1,
418       &GNUNET_GETOPT_set_string, &lookup_type},
419     {'r', "raw", NULL,
420       gettext_noop ("No unneeded output"), 0,
421       &GNUNET_GETOPT_set_one, &raw},
422     {'p', "public-key", "PKEY",
423       gettext_noop ("Specify the public key of the zone to lookup the record in"), 1,
424       &GNUNET_GETOPT_set_string, &public_key},
425     {'z', "zone", "NAME",
426       gettext_noop ("Specify the name of the ego of the zone to lookup the record in"), 1,
427       &GNUNET_GETOPT_set_string, &zone_ego_name},
428     GNUNET_GETOPT_OPTION_END
429   };
430   int ret;
431
432   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
433     return 2;
434
435   GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
436   ret =
437       (GNUNET_OK ==
438        GNUNET_PROGRAM_run (argc, argv, "gnunet-gns",
439                            _("GNUnet GNS resolver tool"), 
440                            options,
441                            &run, NULL)) ? 0 : 1;
442   GNUNET_free ((void*) argv);
443   return ret;
444 }
445
446 /* end of gnunet-gns.c */