-remove deprecated GNUNET_NAMESTORE_RF_AUTHORITY
[oweals/gnunet.git] / src / namestore / gnunet-namestore.c
1
2 /*
3      This file is part of GNUnet.
4      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5
6      GNUnet is free software; you can redistribute it and/or modify
7      it under the terms of the GNU General Public License as published
8      by the Free Software Foundation; either version 3, or (at your
9      option) any later version.
10
11      GNUnet is distributed in the hope that it will be useful, but
12      WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      General Public License for more details.
15
16      You should have received a copy of the GNU General Public License
17      along with GNUnet; see the file COPYING.  If not, write to the
18      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19      Boston, MA 02111-1307, USA.
20 */
21 /**
22  * @file gnunet-namestore.c
23  * @brief command line tool to manipulate the local zone
24  * @author Christian Grothoff
25  *
26  * TODO:
27  * - test
28  * - add options to list/lookup individual records
29  */
30 #include "platform.h"
31 #include <gnunet_util_lib.h>
32 #include <gnunet_dnsparser_lib.h>
33 #include <gnunet_identity_service.h>
34 #include <gnunet_namestore_service.h>
35
36
37 /**
38  * Handle to the namestore.
39  */
40 static struct GNUNET_NAMESTORE_Handle *ns;
41
42 /**
43  * Private key for the our zone.
44  */
45 static struct GNUNET_CRYPTO_EccPrivateKey zone_pkey;
46
47 /**
48  * Handle to identity lookup.
49  */
50 static struct GNUNET_IDENTITY_EgoLookup *el;
51
52 /**
53  * Name of the ego controlling the zone.
54  */
55 static char *ego_name;  
56
57 /**
58  * Desired action is to add a record.
59  */
60 static int add;
61
62 /**
63  * Iterator for the 'add' operation.
64  */
65 static struct GNUNET_NAMESTORE_ZoneIterator *add_zit;
66
67 /**
68  * Queue entry for the 'add-uri' operation.
69  */
70 static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
71
72 /**
73  * Queue entry for the 'add' operation.
74  */
75 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
76
77 /**
78  * Desired action is to list records.
79  */
80 static int list;
81
82 /**
83  * List iterator for the 'list' operation.
84  */
85 static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
86
87 /**
88  * Desired action is to remove a record.
89  */
90 static int del;
91
92 /**
93  * Is record public (opposite of #GNUNET_NAMESTORE_RF_PRIVATE)
94  */
95 static int public;
96
97 /**
98  * Is record a shadow record (#GNUNET_NAMESTORE_RF_SHADOW_RECORD)
99  */
100 static int shadow;
101
102 /**
103  * Queue entry for the 'del' operation.
104  */
105 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
106
107 /**
108  * Name of the records to add/list/remove.
109  */
110 static char *name;
111
112 /**
113  * Value of the record to add/remove.
114  */
115 static char *value;
116
117 /**
118  * URI to import.
119  */
120 static char *uri;
121
122 /**
123  * Type of the record to add/remove, NULL to remove all.
124  */
125 static char *typestring;
126
127 /**
128  * Desired expiration time.
129  */
130 static char *expirationstring;
131
132 /**
133  * Global return value
134  */
135 static int ret;
136
137 /**
138  * Type string converted to DNS type value.
139  */
140 static uint32_t type;
141
142 /**
143  * Value in binary format.
144  */
145 static void *data;
146
147 /**
148  * Number of bytes in 'data'.
149  */
150 static size_t data_size;
151
152 /**
153  * Expirationstring converted to relative time.
154  */
155 static struct GNUNET_TIME_Relative etime_rel;
156
157 /**
158  * Expirationstring converted to absolute time.
159  */
160 static struct GNUNET_TIME_Absolute etime_abs;
161
162 /**
163  * Is expiration time relative or absolute time?
164  */
165 static int etime_is_rel = GNUNET_SYSERR;
166
167 /**
168  * Monitor handle.
169  */
170 static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
171
172 /**
173  * Enables monitor mode.
174  */
175 static int monitor;
176
177
178 /**
179  * Task run on shutdown.  Cleans up everything.
180  *
181  * @param cls unused
182  * @param tc scheduler context
183  */
184 static void
185 do_shutdown (void *cls,
186              const struct GNUNET_SCHEDULER_TaskContext *tc)
187 {
188   if (NULL != el)
189   {
190     GNUNET_IDENTITY_ego_lookup_cancel (el);
191     el = NULL;
192   }
193   if (NULL != list_it)
194   {
195     GNUNET_NAMESTORE_zone_iteration_stop (list_it);
196     list_it = NULL;
197   }
198   if (NULL != add_qe)
199   {
200     GNUNET_NAMESTORE_cancel (add_qe);
201     add_qe = NULL;
202   }
203   if (NULL != add_qe_uri)
204   {
205     GNUNET_NAMESTORE_cancel (add_qe_uri);
206     add_qe_uri = NULL;
207   }
208   if (NULL != del_qe)
209   {
210     GNUNET_NAMESTORE_cancel (del_qe);
211     del_qe = NULL;
212   }
213   if (NULL != ns)
214   {
215     GNUNET_NAMESTORE_disconnect (ns);
216     ns = NULL;
217   }
218   memset (&zone_pkey, 0, sizeof (zone_pkey));
219   if (NULL != uri)
220   {
221     GNUNET_free (uri);
222     uri = NULL;
223   }
224   if (NULL != zm)
225   {
226     GNUNET_NAMESTORE_zone_monitor_stop (zm);
227     zm = NULL;
228   }
229   if (NULL != data)
230   {
231     GNUNET_free (data);
232     data = NULL;
233   }
234 }
235
236
237 /**
238  * Continuation called to notify client about result of the
239  * operation.
240  *
241  * @param cls closure, location of the QueueEntry pointer to NULL out
242  * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
243  *                GNUNET_NO if content was already there
244  *                GNUNET_YES (or other positive value) on success
245  * @param emsg NULL on success, otherwise an error message
246  */
247 static void
248 add_continuation (void *cls,
249                   int32_t success,
250                   const char *emsg)
251 {
252   struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
253
254   *qe = NULL;
255   if (GNUNET_YES != success)
256   {
257     fprintf (stderr,
258              _("Adding record failed: %s\n"),
259              (GNUNET_NO == success) ? "record exists" : emsg);
260     if (GNUNET_NO != success)
261       ret = 1;
262   }
263   if ( (NULL == add_qe) &&
264        (NULL == add_qe_uri) &&
265        (NULL == del_qe) &&
266        (NULL == list_it) )
267     GNUNET_SCHEDULER_shutdown ();
268 }
269
270
271 /**
272  * Continuation called to notify client about result of the
273  * operation.
274  *
275  * @param cls closure, unused
276  * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
277  *                GNUNET_NO if content was already there
278  *                GNUNET_YES (or other positive value) on success
279  * @param emsg NULL on success, otherwise an error message
280  */
281 static void
282 del_continuation (void *cls,
283                   int32_t success,
284                   const char *emsg)
285 {
286   del_qe = NULL;
287   if (success != GNUNET_YES)
288     fprintf (stderr,
289              _("Deleting record failed: %s\n"),
290              emsg);
291   if ( (NULL == add_qe) &&
292        (NULL == add_qe_uri) &&
293        (NULL == list_it) )
294     GNUNET_SCHEDULER_shutdown ();
295 }
296
297
298 /**
299  * Process a record that was stored in the namestore.
300  *
301  * @param cls closure
302  * @param zone_key private key of the zone
303  * @param name name that is being mapped (at most 255 characters long)
304  * @param rd_len number of entries in 'rd' array
305  * @param rd array of records with data to store
306  */
307 static void
308 display_record (void *cls,
309                 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
310                 const char *name,
311                 unsigned int rd_len,
312                 const struct GNUNET_NAMESTORE_RecordData *rd)
313 {
314   const char *typestring;
315   char *s;
316   unsigned int i;
317
318   if (NULL == name)
319   {
320     list_it = NULL;
321     if ( (NULL == del_qe) &&
322          (NULL == add_qe_uri) &&
323          (NULL == add_qe) )
324       GNUNET_SCHEDULER_shutdown ();
325     return;
326   }
327   FPRINTF (stdout,
328            "%s:\n",
329            name);
330   for (i=0;i<rd_len;i++)
331   {
332     typestring = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
333     s = GNUNET_NAMESTORE_value_to_string (rd[i].record_type,
334                                           rd[i].data,
335                                           rd[i].data_size);
336     if (NULL == s)
337     {
338       FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
339                (unsigned int) rd[i].record_type);
340       continue;
341     }
342     FPRINTF (stdout, 
343              "\t%s: %s\n",
344              typestring, 
345              s);
346     GNUNET_free (s);    
347   }
348   FPRINTF (stdout, "%s", "\n");
349   GNUNET_NAMESTORE_zone_iterator_next (list_it);
350 }
351
352
353 /**
354  * Function called once we are in sync in monitor mode.
355  *
356  * @param cls NULL
357  */
358 static void
359 sync_cb (void *cls)
360 {
361   FPRINTF (stdout, "%s", "Monitor is now in sync.\n");
362 }
363
364
365 /**
366  * We're storing a record; this function is given the existing record
367  * so that we can merge the information.
368  *
369  * @param cls closure, unused
370  * @param zone_key private key of the zone
371  * @param rec_name name that is being mapped (at most 255 characters long)
372  * @param rd_count number of entries in 'rd' array
373  * @param rd array of records with data to store
374  */
375 static void
376 get_existing_record (void *cls,
377                      const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
378                      const char *rec_name,
379                      unsigned int rd_count,
380                      const struct GNUNET_NAMESTORE_RecordData *rd)
381 {
382   struct GNUNET_NAMESTORE_RecordData rdn[rd_count + 1];
383   struct GNUNET_NAMESTORE_RecordData *rde;
384
385   if ( (NULL != zone_key) &&
386        (0 != strcmp (rec_name, name)) )
387   {
388     GNUNET_NAMESTORE_zone_iterator_next (add_zit);
389     return;
390   }
391   memset (rdn, 0, sizeof (struct GNUNET_NAMESTORE_RecordData));
392   memcpy (&rdn[1], rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
393   /* FIXME: should add some logic to overwrite records if there
394      can only be one record of a particular type, and to check
395      if the combination of records is valid to begin with... */
396   rde = &rdn[0];
397   rde->data = data;
398   rde->data_size = data_size;
399   rde->record_type = type;
400   if (1 != shadow)
401     rde->flags |= GNUNET_NAMESTORE_RF_SHADOW_RECORD;
402   if (1 != public)
403     rde->flags |= GNUNET_NAMESTORE_RF_PRIVATE;
404   GNUNET_assert (NULL != name);
405   add_qe = GNUNET_NAMESTORE_records_store (ns,
406                                            &zone_pkey,
407                                            name,
408                                            rd_count + 1,
409                                            rde,
410                                            &add_continuation,
411                                            &add_qe);
412   GNUNET_NAMESTORE_zone_iteration_stop (add_zit);
413   add_zit = NULL;
414 }
415
416
417 /**
418  * Function called with the result from the check if the namestore
419  * service is actually running.  If it is, we start the actual
420  * operation.
421  *
422  * @param cls closure with our configuration
423  * @param result GNUNET_YES if the namestore service is running
424  */
425 static void
426 testservice_task (void *cls,
427                   int result)
428 {
429   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
430   struct GNUNET_CRYPTO_EccPublicKey pub;
431   struct GNUNET_NAMESTORE_RecordData rd;
432
433   if (GNUNET_YES != result)
434   {
435     FPRINTF (stderr, _("Service `%s' is not running\n"), 
436              "namestore");
437     return;
438   }
439   if (! (add|del|list|(NULL != uri)))
440   {
441     /* nothing more to be done */  
442     fprintf (stderr,
443              _("No options given\n"));
444     return; 
445   }
446   GNUNET_CRYPTO_ecc_key_get_public (&zone_pkey,
447                                     &pub);
448
449   ns = GNUNET_NAMESTORE_connect (cfg);
450   if (NULL == ns)
451   {
452     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
453                 _("Failed to connect to namestore\n"));
454     return;
455   }
456   if (add)
457   {
458     if (NULL == name)
459     {
460       fprintf (stderr,
461                _("Missing option `%s' for operation `%s'\n"),
462                "-n", _("add"));
463       GNUNET_SCHEDULER_shutdown ();
464       ret = 1;    
465       return;     
466     }
467     if (NULL == typestring)
468     {
469       fprintf (stderr,
470                _("Missing option `%s' for operation `%s'\n"),
471                "-t", _("add"));
472       GNUNET_SCHEDULER_shutdown ();
473       ret = 1;
474       return;     
475     }
476     type = GNUNET_NAMESTORE_typename_to_number (typestring);
477     if (UINT32_MAX == type)
478     {
479       fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
480       GNUNET_SCHEDULER_shutdown ();
481       ret = 1;
482       return;
483     }
484     if (NULL == value)
485     {
486       fprintf (stderr,
487                _("Missing option `%s' for operation `%s'\n"),
488                "-V", _("add"));
489       ret = 1;   
490       GNUNET_SCHEDULER_shutdown ();
491       return;     
492     }
493     if (GNUNET_OK !=
494         GNUNET_NAMESTORE_string_to_value (type,
495                                           value,
496                                           &data,
497                                           &data_size))
498     {
499       fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
500                value,
501                typestring);
502       GNUNET_SCHEDULER_shutdown ();
503       ret = 1;
504       return;
505     }
506     if (NULL == expirationstring)
507     {
508       fprintf (stderr,
509                _("Missing option `%s' for operation `%s'\n"),
510                "-e", _("add"));
511       GNUNET_SCHEDULER_shutdown ();
512       ret = 1;    
513       return;     
514     }
515     if (0 == strcmp (expirationstring, "never"))
516     {
517       etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
518       etime_is_rel = GNUNET_NO;
519     }
520     else if (GNUNET_OK ==
521              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
522                                                     &etime_rel))
523     {
524       etime_is_rel = GNUNET_YES;
525     }
526     else if (GNUNET_OK == 
527              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
528                                                     &etime_abs))
529     {
530       etime_is_rel = GNUNET_NO;
531     }
532     else
533     {
534       fprintf (stderr,
535                _("Invalid time format `%s'\n"),
536                expirationstring);
537       GNUNET_SCHEDULER_shutdown ();
538       ret = 1;
539       return;     
540     }
541     add_zit = GNUNET_NAMESTORE_zone_iteration_start (ns,
542                                                      &zone_pkey,
543                                                      &get_existing_record,
544                                                      NULL);
545   }
546   if (del)
547   {
548     if (NULL == name)
549     {
550       fprintf (stderr,
551                _("Missing option `%s' for operation `%s'\n"),
552                "-n", _("del"));
553       GNUNET_SCHEDULER_shutdown ();
554       ret = 1;
555       return;     
556     }
557     del_qe = GNUNET_NAMESTORE_records_store (ns,
558                                              &zone_pkey,
559                                              name,
560                                              0, NULL,
561                                              &del_continuation,
562                                              NULL);
563   }
564   if (list)
565   {
566     list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
567                                                      &zone_pkey,
568                                                      &display_record,
569                                                      NULL);
570   }
571   if (NULL != uri)
572   {
573     char sh[105];
574     char sname[64];
575     struct GNUNET_CRYPTO_EccPublicKey pkey;
576
577     if ( (2 != (sscanf (uri,
578                         "gnunet://gns/%104s/%63s",
579                         sh,
580                         sname)) ) ||
581          (GNUNET_OK !=
582           GNUNET_CRYPTO_ecc_public_key_from_string (sh, strlen (sh), &pkey)) )
583     {
584       fprintf (stderr, 
585                _("Invalid URI `%s'\n"),
586                uri);
587       GNUNET_SCHEDULER_shutdown ();
588       ret = 1;
589       return;
590     }
591     memset (&rd, 0, sizeof (rd));
592     rd.data = &pkey;
593     rd.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicKey);
594     rd.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
595     if (GNUNET_YES == etime_is_rel)
596     {
597       rd.expiration_time = etime_rel.rel_value_us;
598       rd.flags |= GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
599     }
600     else if (GNUNET_NO == etime_is_rel)
601       rd.expiration_time = etime_abs.abs_value_us;
602     else    
603       rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
604     if (1 != shadow)
605       rd.flags |= GNUNET_NAMESTORE_RF_SHADOW_RECORD;
606     add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
607                                                  &zone_pkey,
608                                                  sname,
609                                                  1,
610                                                  &rd,
611                                                  &add_continuation,
612                                                  &add_qe_uri);
613   }
614   if (monitor)
615   {
616     zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
617                                               &zone_pkey,
618                                               &display_record,
619                                               &sync_cb,
620                                               NULL);
621   }
622 }
623
624
625 /**
626  * Callback invoked from identity service with ego information.
627  * An @a ego of NULL means the ego was not found.
628  *
629  * @param cls closure with the configuration
630  * @param ego an ego known to identity service, or NULL 
631  */
632 static void
633 identity_cb (void *cls,
634              const struct GNUNET_IDENTITY_Ego *ego)
635 {
636   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
637
638   el = NULL;
639   if (NULL == ego)
640   {
641     fprintf (stderr, 
642              _("Ego `%s' not known to identity service\n"),
643              ego_name);
644     return;
645   }
646   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
647   GNUNET_free (ego_name);
648   ego_name = NULL;
649   GNUNET_CLIENT_service_test ("namestore", cfg,
650                               GNUNET_TIME_UNIT_SECONDS,
651                               &testservice_task,
652                               (void *) cfg);
653 }
654
655
656 /**
657  * Main function that will be run.
658  *
659  * @param cls closure
660  * @param args remaining command-line arguments
661  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
662  * @param cfg configuration
663  */
664 static void
665 run (void *cls, char *const *args, const char *cfgfile,
666      const struct GNUNET_CONFIGURATION_Handle *cfg)
667 {
668   if (NULL == ego_name)
669   {
670     fprintf (stderr, 
671              _("You must specify which zone should be accessed\n"));
672     return;
673   }
674   if ( (NULL != args[0]) && (NULL == uri) )
675     uri = GNUNET_strdup (args[0]);
676   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
677                                 &do_shutdown, NULL);
678   el = GNUNET_IDENTITY_ego_lookup (cfg,
679                                    ego_name,
680                                    &identity_cb,
681                                    (void *) cfg);
682 }
683
684
685 /**
686  * The main function for gnunet-namestore.
687  *
688  * @param argc number of arguments from the command line
689  * @param argv command line arguments
690  * @return 0 ok, 1 on error
691  */
692 int
693 main (int argc, char *const *argv)
694 {
695   nonauthority = -1;
696   public = -1;
697
698   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
699     {'a', "add", NULL,
700      gettext_noop ("add record"), 0,
701      &GNUNET_GETOPT_set_one, &add},
702     {'d', "delete", NULL,
703      gettext_noop ("delete record"), 0,
704      &GNUNET_GETOPT_set_one, &del},   
705     {'D', "display", NULL,
706      gettext_noop ("display records"), 0,
707      &GNUNET_GETOPT_set_one, &list},   
708     {'e', "expiration", "TIME",
709      gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"), 1,
710      &GNUNET_GETOPT_set_string, &expirationstring},   
711     {'m', "monitor", NULL,
712      gettext_noop ("monitor changes in the namestore"), 0,
713      &GNUNET_GETOPT_set_one, &monitor},   
714     {'n', "name", "NAME",
715      gettext_noop ("name of the record to add/delete/display"), 1,
716      &GNUNET_GETOPT_set_string, &name},   
717     {'t', "type", "TYPE",
718      gettext_noop ("type of the record to add/delete/display"), 1,
719      &GNUNET_GETOPT_set_string, &typestring},   
720     {'u', "uri", "URI",
721      gettext_noop ("URI to import into our zone"), 1,
722      &GNUNET_GETOPT_set_string, &uri},   
723     {'V', "value", "VALUE",
724      gettext_noop ("value of the record to add/delete"), 1,
725      &GNUNET_GETOPT_set_string, &value},   
726     {'p', "public", NULL,
727      gettext_noop ("create or list public record"), 0,
728      &GNUNET_GETOPT_set_one, &public},
729     {'s', "shadow", NULL,
730      gettext_noop ("create shadow record (only valid if all other records of the same type have expired"), 0,
731      &GNUNET_GETOPT_set_one, &shadow},
732     {'z', "zone", "EGO",
733      gettext_noop ("name of the ego controlling the zone"), 1,
734      &GNUNET_GETOPT_set_string, &ego_name},   
735     GNUNET_GETOPT_OPTION_END
736   };
737
738   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
739     return 2;
740
741   GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
742   if (GNUNET_OK !=
743       GNUNET_PROGRAM_run (argc, argv, "gnunet-namestore",
744                           _("GNUnet zone manipulation tool"), 
745                           options,
746                           &run, NULL))
747   {
748     GNUNET_free ((void*) argv);
749     return 1;
750   }
751   GNUNET_free ((void*) argv);
752   return ret;
753 }
754
755 /* end of gnunet-namestore.c */