Merge branch 'master' of gnunet.org:gnunet
[oweals/gnunet.git] / src / namestore / gnunet-namestore.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2013, 2014 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file gnunet-namestore.c
22  * @brief command line tool to manipulate the local zone
23  * @author Christian Grothoff
24  *
25  * TODO:
26  * - test
27  */
28 #include "platform.h"
29 #include <gnunet_util_lib.h>
30 #include <gnunet_dnsparser_lib.h>
31 #include <gnunet_identity_service.h>
32 #include <gnunet_gnsrecord_lib.h>
33 #include <gnunet_gns_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_EcdsaPrivateKey zone_pkey;
46
47 /**
48  * Handle to identity lookup.
49  */
50 static struct GNUNET_IDENTITY_EgoLookup *el;
51
52 /**
53  * Identity service handle
54  */
55 static struct GNUNET_IDENTITY_Handle *idh;
56
57 /**
58  * Obtain default ego
59  */
60 struct GNUNET_IDENTITY_Operation *get_default;
61
62 /**
63  * Name of the ego controlling the zone.
64  */
65 static char *ego_name;
66
67 /**
68  * Desired action is to add a record.
69  */
70 static int add;
71
72 /**
73  * Queue entry for the 'add-uri' operation.
74  */
75 static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
76
77 /**
78  * Queue entry for the 'add' operation.
79  */
80 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
81
82 /**
83  * Queue entry for the 'lookup' operation.
84  */
85 static struct GNUNET_NAMESTORE_QueueEntry *get_qe;
86
87 /**
88  * Queue entry for the 'reverse lookup' operation (in combination with a name).
89  */
90 static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
91
92 /**
93  * Desired action is to list records.
94  */
95 static int list;
96
97 /**
98  * List iterator for the 'list' operation.
99  */
100 static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
101
102 /**
103  * Desired action is to remove a record.
104  */
105 static int del;
106
107 /**
108  * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
109  */
110 static int is_public;
111
112 /**
113  * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW_RECORD)
114  */
115 static int is_shadow;
116
117 /**
118  * Queue entry for the 'del' operation.
119  */
120 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
121
122 /**
123  * Name of the records to add/list/remove.
124  */
125 static char *name;
126
127 /**
128  * Value of the record to add/remove.
129  */
130 static char *value;
131
132 /**
133  * URI to import.
134  */
135 static char *uri;
136
137 /**
138  * Reverse lookup to perform.
139  */
140 static char *reverse_pkey;
141
142 /**
143  * Type of the record to add/remove, NULL to remove all.
144  */
145 static char *typestring;
146
147 /**
148  * Desired expiration time.
149  */
150 static char *expirationstring;
151
152 /**
153  * Desired nick name.
154  */
155 static char *nickstring;
156
157 /**
158  * Global return value
159  */
160 static int ret;
161
162 /**
163  * Type string converted to DNS type value.
164  */
165 static uint32_t type;
166
167 /**
168  * Value in binary format.
169  */
170 static void *data;
171
172 /**
173  * Number of bytes in #data.
174  */
175 static size_t data_size;
176
177 /**
178  * Expirationstring converted to relative time.
179  */
180 static struct GNUNET_TIME_Relative etime_rel;
181
182 /**
183  * Expirationstring converted to absolute time.
184  */
185 static struct GNUNET_TIME_Absolute etime_abs;
186
187 /**
188  * Is expiration time relative or absolute time?
189  */
190 static int etime_is_rel = GNUNET_SYSERR;
191
192 /**
193  * Monitor handle.
194  */
195 static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
196
197 /**
198  * Enables monitor mode.
199  */
200 static int monitor;
201
202
203 /**
204  * Task run on shutdown.  Cleans up everything.
205  *
206  * @param cls unused
207  */
208 static void
209 do_shutdown (void *cls)
210 {
211   (void) cls;
212   if (NULL != get_default)
213   {
214     GNUNET_IDENTITY_cancel (get_default);
215     get_default = NULL;
216   }
217   if (NULL != idh)
218   {
219     GNUNET_IDENTITY_disconnect (idh);
220     idh = NULL;
221   }
222   if (NULL != el)
223   {
224     GNUNET_IDENTITY_ego_lookup_cancel (el);
225     el = NULL;
226   }
227   if (NULL != list_it)
228   {
229     GNUNET_NAMESTORE_zone_iteration_stop (list_it);
230     list_it = NULL;
231   }
232   if (NULL != add_qe)
233   {
234     GNUNET_NAMESTORE_cancel (add_qe);
235     add_qe = NULL;
236   }
237   if (NULL != add_qe_uri)
238   {
239     GNUNET_NAMESTORE_cancel (add_qe_uri);
240     add_qe_uri = NULL;
241   }
242   if (NULL != get_qe)
243   {
244     GNUNET_NAMESTORE_cancel (get_qe);
245     get_qe = NULL;
246   }
247   if (NULL != del_qe)
248   {
249     GNUNET_NAMESTORE_cancel (del_qe);
250     del_qe = NULL;
251   }
252   if (NULL != ns)
253   {
254     GNUNET_NAMESTORE_disconnect (ns);
255     ns = NULL;
256   }
257   memset (&zone_pkey, 0, sizeof (zone_pkey));
258   if (NULL != uri)
259   {
260     GNUNET_free (uri);
261     uri = NULL;
262   }
263   if (NULL != zm)
264   {
265     GNUNET_NAMESTORE_zone_monitor_stop (zm);
266     zm = NULL;
267   }
268   if (NULL != data)
269   {
270     GNUNET_free (data);
271     data = NULL;
272   }
273 }
274
275
276 /**
277  * Check if we are finished, and if so, perform shutdown.
278  */
279 static void
280 test_finished ()
281 {
282   if ( (NULL == add_qe) &&
283        (NULL == add_qe_uri) &&
284        (NULL == get_qe) &&
285        (NULL == del_qe) &&
286        (NULL == reverse_qe) &&
287        (NULL == list_it) )
288     GNUNET_SCHEDULER_shutdown ();
289 }
290
291
292 /**
293  * Continuation called to notify client about result of the
294  * operation.
295  *
296  * @param cls closure, location of the QueueEntry pointer to NULL out
297  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
298  *                #GNUNET_NO if content was already there
299  *                #GNUNET_YES (or other positive value) on success
300  * @param emsg NULL on success, otherwise an error message
301  */
302 static void
303 add_continuation (void *cls,
304                   int32_t success,
305                   const char *emsg)
306 {
307   struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
308
309   *qe = NULL;
310   if (GNUNET_YES != success)
311   {
312     fprintf (stderr,
313              _("Adding record failed: %s\n"),
314              (GNUNET_NO == success) ? "record exists" : emsg);
315     if (GNUNET_NO != success)
316       ret = 1;
317   }
318   ret = 0;
319   test_finished ();
320 }
321
322
323 /**
324  * Continuation called to notify client about result of the
325  * operation.
326  *
327  * @param cls closure, unused
328  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
329  *                #GNUNET_NO if content was already there
330  *                #GNUNET_YES (or other positive value) on success
331  * @param emsg NULL on success, otherwise an error message
332  */
333 static void
334 del_continuation (void *cls,
335                   int32_t success,
336                   const char *emsg)
337 {
338   (void) cls;
339   del_qe = NULL;
340   if (GNUNET_NO == success)
341   {
342     fprintf (stderr,
343              _("Deleting record failed, record does not exist%s%s\n"),
344              (NULL != emsg) ? ": " : "",
345              (NULL != emsg) ? emsg : "");
346   }
347   if (GNUNET_SYSERR == success)
348   {
349     fprintf (stderr,
350              _("Deleting record failed%s%s\n"),
351              (NULL != emsg) ? ": " : "",
352              (NULL != emsg) ? emsg : "");
353   }
354   test_finished ();
355 }
356
357
358 /**
359  * Function called when we are done with a zone iteration.
360  */
361 static void
362 zone_iteration_finished (void *cls)
363 {
364   (void) cls;
365   list_it = NULL;
366   test_finished ();
367 }
368
369
370 /**
371  * Function called when we encountered an error in a zone iteration.
372  */
373 static void
374 zone_iteration_error_cb (void *cls)
375 {
376   (void) cls;
377   list_it = NULL;
378   fprintf (stderr,
379            "Error iterating over zone\n");
380   ret = 1;
381   test_finished ();
382 }
383
384
385 /**
386  * Process a record that was stored in the namestore.
387  *
388  * @param rname name that is being mapped (at most 255 characters long)
389  * @param rd_len number of entries in @a rd array
390  * @param rd array of records with data to store
391  */
392 static void
393 display_record (const char *rname,
394                 unsigned int rd_len,
395                 const struct GNUNET_GNSRECORD_Data *rd)
396 {
397   const char *typestring;
398   char *s;
399   const char *ets;
400   struct GNUNET_TIME_Absolute at;
401   struct GNUNET_TIME_Relative rt;
402
403   if ( (NULL != name) &&
404        (0 != strcmp (name, rname)) )
405   {
406     GNUNET_NAMESTORE_zone_iterator_next (list_it,
407                                          1);
408     return;
409   }
410   FPRINTF (stdout,
411            "%s:\n",
412            rname);
413   for (unsigned int i=0;i<rd_len;i++)
414   {
415     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
416          (0 != strcmp (rname,
417                        GNUNET_GNS_EMPTY_LABEL_AT)) )
418       continue;
419     typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
420     s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
421                                           rd[i].data,
422                                           rd[i].data_size);
423     if (NULL == s)
424     {
425       FPRINTF (stdout,
426                _("\tCorrupt or unsupported record of type %u\n"),
427                (unsigned int) rd[i].record_type);
428       continue;
429     }
430     if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
431     {
432       rt.rel_value_us = rd[i].expiration_time;
433       ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
434     }
435     else
436     {
437       at.abs_value_us = rd[i].expiration_time;
438       ets = GNUNET_STRINGS_absolute_time_to_string (at);
439     }
440     FPRINTF (stdout,
441              "\t%s: %s (%s)\t%s\t%s\n",
442              typestring,
443              s,
444              ets,
445              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE" : "PUBLIC",
446              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) ? "SHADOW" : "");
447     GNUNET_free (s);
448   }
449   FPRINTF (stdout, "%s", "\n");
450 }
451
452
453 /**
454  * Process a record that was stored in the namestore.
455  *
456  * @param cls closure
457  * @param zone_key private key of the zone
458  * @param rname name that is being mapped (at most 255 characters long)
459  * @param rd_len number of entries in @a rd array
460  * @param rd array of records with data to store
461  */
462 static void
463 display_record_iterator (void *cls,
464                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
465                          const char *rname,
466                          unsigned int rd_len,
467                          const struct GNUNET_GNSRECORD_Data *rd)
468 {
469   (void) cls;
470   (void) zone_key;
471   display_record (rname,
472                   rd_len,
473                   rd);
474   GNUNET_NAMESTORE_zone_iterator_next (list_it,
475                                        1);
476 }
477
478
479 /**
480  * Process a record that was stored in the namestore.
481  *
482  * @param cls closure
483  * @param zone_key private key of the zone
484  * @param rname name that is being mapped (at most 255 characters long)
485  * @param rd_len number of entries in @a rd array
486  * @param rd array of records with data to store
487  */
488 static void
489 display_record_monitor (void *cls,
490                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
491                         const char *rname,
492                         unsigned int rd_len,
493                         const struct GNUNET_GNSRECORD_Data *rd)
494 {
495   (void) cls;
496   (void) zone_key;
497   display_record (rname,
498                   rd_len,
499                   rd);
500   GNUNET_NAMESTORE_zone_monitor_next (zm,
501                                       1);
502 }
503
504
505 /**
506  * Process a record that was stored in the namestore.
507  *
508  * @param cls closure
509  * @param zone_key private key of the zone
510  * @param rname name that is being mapped (at most 255 characters long)
511  * @param rd_len number of entries in @a rd array
512  * @param rd array of records with data to store
513  */
514 static void
515 display_record_lookup (void *cls,
516                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
517                        const char *rname,
518                        unsigned int rd_len,
519                        const struct GNUNET_GNSRECORD_Data *rd)
520 {
521   get_qe = NULL;
522   display_record (rname,
523                   rd_len,
524                   rd);
525   test_finished ();
526 }
527
528
529 /**
530  * Function called once we are in sync in monitor mode.
531  *
532  * @param cls NULL
533  */
534 static void
535 sync_cb (void *cls)
536 {
537   (void) cls;
538   FPRINTF (stdout,
539            "%s",
540            "Monitor is now in sync.\n");
541 }
542
543
544 /**
545  * Function called on errors while monitoring.
546  *
547  * @param cls NULL
548  */
549 static void
550 monitor_error_cb (void *cls)
551 {
552   (void) cls;
553   FPRINTF (stderr,
554            "%s",
555            "Monitor disconnected and out of sync.\n");
556 }
557
558
559 /**
560  * Function called on errors while monitoring.
561  *
562  * @param cls NULL
563  */
564 static void
565 lookup_error_cb (void *cls)
566 {
567   (void) cls;
568   get_qe = NULL;
569   FPRINTF (stderr,
570            "%s",
571            "Failed to lookup record.\n");
572   test_finished ();
573 }
574
575
576 /**
577  * Function called if lookup fails.
578  */
579 static void
580 add_error_cb (void *cls)
581 {
582   (void) cls;
583   add_qe = NULL;
584   GNUNET_break (0);
585   ret = 1;
586   test_finished ();
587 }
588
589
590 /**
591  * We're storing a record; this function is given the existing record
592  * so that we can merge the information.
593  *
594  * @param cls closure, unused
595  * @param zone_key private key of the zone
596  * @param rec_name name that is being mapped (at most 255 characters long)
597  * @param rd_count number of entries in @a rd array
598  * @param rd array of records with data to store
599  */
600 static void
601 get_existing_record (void *cls,
602                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
603                      const char *rec_name,
604                      unsigned int rd_count,
605                      const struct GNUNET_GNSRECORD_Data *rd)
606 {
607   struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
608   struct GNUNET_GNSRECORD_Data *rde;
609
610   (void) cls;
611   (void) zone_key;
612   add_qe = NULL;
613   if (0 != strcmp (rec_name, name))
614   {
615     GNUNET_break (0);
616     ret = 1;
617     test_finished ();
618     return;
619   }
620
621   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
622               "Received %u records for name `%s'\n",
623               rd_count, rec_name);
624   for (unsigned int i=0;i<rd_count;i++)
625   {
626     switch (rd[i].record_type)
627     {
628     case GNUNET_DNSPARSER_TYPE_CNAME:
629       fprintf (stderr,
630                _("A %s record exists already under `%s', no other records can be added.\n"),
631                "CNAME",
632                rec_name);
633       ret = 1;
634       test_finished ();
635       return;
636     case GNUNET_GNSRECORD_TYPE_PKEY:
637       fprintf (stderr,
638                _("A %s record exists already under `%s', no other records can be added.\n"),
639                "PKEY",
640                rec_name);
641       ret = 1;
642       test_finished ();
643       return;
644     case GNUNET_GNSRECORD_TYPE_GNS2DNS:
645       fprintf (stderr,
646                _("A %s record exists already under `%s', no other records can be added.\n"),
647                "GNS2DNS",
648                rec_name);
649       ret = 1;
650       test_finished ();
651       return;
652     }
653   }
654   switch (type)
655   {
656   case GNUNET_DNSPARSER_TYPE_CNAME:
657     if (0 != rd_count)
658     {
659       fprintf (stderr,
660                _("Records already exist under `%s', cannot add `%s' record.\n"),
661                rec_name,
662                "CNAME");
663       ret = 1;
664       test_finished ();
665       return;
666     }
667     break;
668   case GNUNET_GNSRECORD_TYPE_PKEY:
669     if (0 != rd_count)
670     {
671       fprintf (stderr,
672                _("Records already exist under `%s', cannot add `%s' record.\n"),
673                rec_name,
674                "PKEY");
675       ret = 1;
676       test_finished ();
677       return;
678     }
679     break;
680   case GNUNET_GNSRECORD_TYPE_GNS2DNS:
681     if (0 != rd_count)
682     {
683       fprintf (stderr,
684                _("Records already exist under `%s', cannot add `%s' record.\n"),
685                rec_name,
686                "GNS2DNS");
687       ret = 1;
688       test_finished ();
689       return;
690     }
691     break;
692   }
693   memset (rdn,
694           0,
695           sizeof (struct GNUNET_GNSRECORD_Data));
696   GNUNET_memcpy (&rdn[1],
697                  rd,
698                  rd_count * sizeof (struct GNUNET_GNSRECORD_Data));
699   rde = &rdn[0];
700   rde->data = data;
701   rde->data_size = data_size;
702   rde->record_type = type;
703   if (1 == is_shadow)
704     rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
705   if (1 != is_public)
706     rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
707   if (GNUNET_YES == etime_is_rel)
708   {
709     rde->expiration_time = etime_rel.rel_value_us;
710     rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
711   }
712   else if (GNUNET_NO == etime_is_rel)
713     rde->expiration_time = etime_abs.abs_value_us;
714   else
715     rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
716   GNUNET_assert (NULL != name);
717   add_qe = GNUNET_NAMESTORE_records_store (ns,
718                                            &zone_pkey,
719                                            name,
720                                            rd_count + 1,
721                                            rde,
722                                            &add_continuation,
723                                            &add_qe);
724 }
725
726
727 /**
728  * Function called if we encountered an error in zone-to-name.
729  */
730 static void
731 reverse_error_cb (void *cls)
732 {
733   (void) cls;
734   reverse_qe = NULL;
735   FPRINTF (stdout,
736            "%s.zkey\n",
737            reverse_pkey);
738 }
739
740
741 /**
742  * Function called with the result of our attempt to obtain a name for a given
743  * public key.
744  *
745  * @param cls NULL
746  * @param zone private key of the zone; NULL on disconnect
747  * @param label label of the records; NULL on disconnect
748  * @param rd_count number of entries in @a rd array, 0 if label was deleted
749  * @param rd array of records with data to store
750  */
751 static void
752 handle_reverse_lookup (void *cls,
753                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
754                        const char *label,
755                        unsigned int rd_count,
756                        const struct GNUNET_GNSRECORD_Data *rd)
757 {
758   (void) cls;
759   (void) zone;
760   (void) rd_count;
761   (void) rd;
762   reverse_qe = NULL;
763   if (NULL == label)
764     FPRINTF (stdout,
765              "%s.zkey\n",
766              reverse_pkey);
767   else
768     FPRINTF (stdout,
769              "%s.gnu\n",
770              label);
771   test_finished ();
772 }
773
774
775 /**
776  * Function called if lookup for deletion fails.
777  */
778 static void
779 del_lookup_error_cb (void *cls)
780 {
781   (void) cls;
782   del_qe = NULL;
783   GNUNET_break (0);
784   ret = 1;
785   test_finished ();
786 }
787
788
789 /**
790  * We were asked to delete something; this function is called with
791  * the existing records. Now we should determine what should be
792  * deleted and then issue the deletion operation.
793  *
794  * @param cls NULL
795  * @param zone private key of the zone we are deleting from
796  * @param label name of the records we are editing
797  * @param rd_count size of the @a rd array
798  * @param rd existing records
799  */
800 static void
801 del_monitor (void *cls,
802              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
803              const char *label,
804              unsigned int rd_count,
805              const struct GNUNET_GNSRECORD_Data *rd)
806 {
807   struct GNUNET_GNSRECORD_Data rdx[rd_count];
808   unsigned int rd_left;
809   uint32_t type;
810   char *vs;
811
812   (void) cls;
813   (void) zone;
814   del_qe = NULL;
815   if (0 == rd_count)
816   {
817     FPRINTF (stderr,
818              _("There are no records under label `%s' that could be deleted.\n"),
819              label);
820     ret = 1;
821     test_finished ();
822     return;
823   }
824   if ( (NULL == value) &&
825        (NULL == typestring) )
826   {
827     /* delete everything */
828     del_qe = GNUNET_NAMESTORE_records_store (ns,
829                                              &zone_pkey,
830                                              name,
831                                              0,
832                                              NULL,
833                                              &del_continuation,
834                                              NULL);
835     return;
836   }
837   rd_left = 0;
838   if (NULL != typestring)
839     type = GNUNET_GNSRECORD_typename_to_number (typestring);
840   else
841     type = GNUNET_GNSRECORD_TYPE_ANY;
842   for (unsigned int i=0;i<rd_count;i++)
843   {
844     vs = NULL;
845     if (! ( ( (GNUNET_GNSRECORD_TYPE_ANY == type) ||
846               (rd[i].record_type == type) ) &&
847             ( (NULL == value) ||
848               (NULL == (vs = (GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
849                                                                 rd[i].data,
850                                                                 rd[i].data_size)))) ||
851               (0 == strcmp (vs, value)) ) ) )
852       rdx[rd_left++] = rd[i];
853     GNUNET_free_non_null (vs);
854   }
855   if (rd_count == rd_left)
856   {
857     /* nothing got deleted */
858     FPRINTF (stderr,
859              _("There are no records under label `%s' that match the request for deletion.\n"),
860              label);
861     test_finished ();
862     return;
863   }
864   /* delete everything but what we copied to 'rdx' */
865   del_qe = GNUNET_NAMESTORE_records_store (ns,
866                                            &zone_pkey,
867                                            name,
868                                            rd_left,
869                                            rdx,
870                                            &del_continuation,
871                                            NULL);
872 }
873
874
875 /**
876  * Callback invoked from identity service with ego information.
877  * An @a ego of NULL means the ego was not found.
878  *
879  * @param cls closure with the configuration
880  * @param ego an ego known to identity service, or NULL
881  */
882 static void
883 identity_cb (void *cls,
884              const struct GNUNET_IDENTITY_Ego *ego)
885 {
886   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
887   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
888   struct GNUNET_GNSRECORD_Data rd;
889
890   el = NULL;
891   if (NULL == ego)
892   {
893     if (NULL != ego_name)
894     {
895       fprintf (stderr,
896                _("Ego `%s' not known to identity service\n"),
897                ego_name);
898     }
899     GNUNET_SCHEDULER_shutdown ();
900     ret = -1;
901     return;
902   }
903   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
904   GNUNET_free_non_null (ego_name);
905   ego_name = NULL;
906
907   if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)) )
908   {
909     /* nothing more to be done */
910     fprintf (stderr,
911              _("No options given\n"));
912     GNUNET_SCHEDULER_shutdown ();
913     return;
914   }
915   GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
916                                     &pub);
917
918   ns = GNUNET_NAMESTORE_connect (cfg);
919   if (NULL == ns)
920   {
921     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
922                 _("Failed to connect to namestore\n"));
923     return;
924   }
925   if (add)
926   {
927     if (NULL == name)
928     {
929       fprintf (stderr,
930                _("Missing option `%s' for operation `%s'\n"),
931                "-n", _("add"));
932       GNUNET_SCHEDULER_shutdown ();
933       ret = 1;
934       return;
935     }
936     if (NULL == typestring)
937     {
938       fprintf (stderr,
939                _("Missing option `%s' for operation `%s'\n"),
940                "-t", _("add"));
941       GNUNET_SCHEDULER_shutdown ();
942       ret = 1;
943       return;
944     }
945     type = GNUNET_GNSRECORD_typename_to_number (typestring);
946     if (UINT32_MAX == type)
947     {
948       fprintf (stderr,
949                _("Unsupported type `%s'\n"),
950                typestring);
951       GNUNET_SCHEDULER_shutdown ();
952       ret = 1;
953       return;
954     }
955     if (NULL == value)
956     {
957       fprintf (stderr,
958                _("Missing option `%s' for operation `%s'\n"),
959                "-V", _("add"));
960       ret = 1;
961       GNUNET_SCHEDULER_shutdown ();
962       return;
963     }
964     if (GNUNET_OK !=
965         GNUNET_GNSRECORD_string_to_value (type,
966                                           value,
967                                           &data,
968                                           &data_size))
969     {
970       fprintf (stderr,
971                _("Value `%s' invalid for record type `%s'\n"),
972                value,
973                typestring);
974       GNUNET_SCHEDULER_shutdown ();
975       ret = 1;
976       return;
977     }
978     if (NULL == expirationstring)
979     {
980       fprintf (stderr,
981                _("Missing option `%s' for operation `%s'\n"),
982                "-e",
983                _("add"));
984       GNUNET_SCHEDULER_shutdown ();
985       ret = 1;
986       return;
987     }
988     if (0 == strcmp (expirationstring,
989                      "never"))
990     {
991       etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
992       etime_is_rel = GNUNET_NO;
993     }
994     else if (GNUNET_OK ==
995              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
996                                                     &etime_rel))
997     {
998       etime_is_rel = GNUNET_YES;
999       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1000                   "Storing record with relative expiration time of %s\n",
1001                   GNUNET_STRINGS_relative_time_to_string (etime_rel,
1002                                                           GNUNET_NO));
1003     }
1004     else if (GNUNET_OK ==
1005              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
1006                                                     &etime_abs))
1007     {
1008       etime_is_rel = GNUNET_NO;
1009       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1010                   "Storing record with absolute expiration time of %s\n",
1011                   GNUNET_STRINGS_absolute_time_to_string (etime_abs));
1012     }
1013     else
1014     {
1015       fprintf (stderr,
1016                _("Invalid time format `%s'\n"),
1017                expirationstring);
1018       GNUNET_SCHEDULER_shutdown ();
1019       ret = 1;
1020       return;
1021     }
1022     add_qe = GNUNET_NAMESTORE_records_lookup (ns,
1023                                               &zone_pkey,
1024                                               name,
1025                                               &add_error_cb,
1026                                               NULL,
1027                                               &get_existing_record,
1028                                               NULL);
1029   }
1030   if (del)
1031   {
1032     if (NULL == name)
1033     {
1034       fprintf (stderr,
1035                _("Missing option `%s' for operation `%s'\n"),
1036                "-n", _("del"));
1037       GNUNET_SCHEDULER_shutdown ();
1038       ret = 1;
1039       return;
1040     }
1041     del_qe = GNUNET_NAMESTORE_records_lookup (ns,
1042                                               &zone_pkey,
1043                                               name,
1044                                               &del_lookup_error_cb,
1045                                               NULL,
1046                                               &del_monitor,
1047                                               NULL);
1048   }
1049   if (list)
1050   {
1051     if (NULL != name)
1052       get_qe = GNUNET_NAMESTORE_records_lookup (ns,
1053                                                 &zone_pkey,
1054                                                 name,
1055                                                 &lookup_error_cb,
1056                                                 NULL,
1057                                                 &display_record_lookup,
1058                                                 NULL);
1059     else
1060       list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
1061                                                        &zone_pkey,
1062                                                        &zone_iteration_error_cb,
1063                                                        NULL,
1064                                                        &display_record_iterator,
1065                                                        NULL,
1066                                                        &zone_iteration_finished,
1067                                                        NULL);
1068   }
1069   if (NULL != reverse_pkey)
1070   {
1071     struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1072
1073     if (GNUNET_OK !=
1074         GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
1075                                                     strlen (reverse_pkey),
1076                                                     &pubkey))
1077     {
1078       fprintf (stderr,
1079                _("Invalid public key for reverse lookup `%s'\n"),
1080                reverse_pkey);
1081       GNUNET_SCHEDULER_shutdown ();
1082     }
1083     reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
1084                                                 &zone_pkey,
1085                                                 &pubkey,
1086                                                 &reverse_error_cb,
1087                                                 NULL,
1088                                                 &handle_reverse_lookup,
1089                                                 NULL);
1090   }
1091   if (NULL != uri)
1092   {
1093     char sh[105];
1094     char sname[64];
1095     struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1096
1097     GNUNET_STRINGS_utf8_tolower (uri, uri);
1098     if ( (2 != (sscanf (uri,
1099                         "gnunet://gns/%52s/%63s",
1100                         sh,
1101                         sname)) ) ||
1102          (GNUNET_OK !=
1103           GNUNET_CRYPTO_ecdsa_public_key_from_string (sh,
1104                                                       strlen (sh),
1105                                                       &pkey)) )
1106     {
1107       fprintf (stderr,
1108                _("Invalid URI `%s'\n"),
1109                uri);
1110       GNUNET_SCHEDULER_shutdown ();
1111       ret = 1;
1112       return;
1113     }
1114     memset (&rd, 0, sizeof (rd));
1115     rd.data = &pkey;
1116     rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1117     rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
1118     if (GNUNET_YES == etime_is_rel)
1119     {
1120       rd.expiration_time = etime_rel.rel_value_us;
1121       rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1122     }
1123     else if (GNUNET_NO == etime_is_rel)
1124       rd.expiration_time = etime_abs.abs_value_us;
1125     else
1126       rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
1127
1128     if (1 == is_shadow)
1129       rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1130     add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
1131                                                  &zone_pkey,
1132                                                  sname,
1133                                                  1,
1134                                                  &rd,
1135                                                  &add_continuation,
1136                                                  &add_qe_uri);
1137   }
1138   if (NULL != nickstring)
1139   {
1140     if (0 == strlen(nickstring))
1141     {
1142       fprintf (stderr,
1143                _("Invalid nick `%s'\n"),
1144                nickstring);
1145       GNUNET_SCHEDULER_shutdown ();
1146       ret = 1;
1147       return;
1148     }
1149     add_qe_uri = GNUNET_NAMESTORE_set_nick (ns,
1150                                             &zone_pkey,
1151                                             nickstring,
1152                                             &add_continuation,
1153                                             &add_qe_uri);
1154   }
1155   if (monitor)
1156   {
1157     zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
1158                                               &zone_pkey,
1159                                               GNUNET_YES,
1160                                               &monitor_error_cb,
1161                                               NULL,
1162                                               &display_record_monitor,
1163                                               NULL,
1164                                               &sync_cb,
1165                                               NULL);
1166   }
1167 }
1168
1169
1170 static void
1171 default_ego_cb (void *cls,
1172                 struct GNUNET_IDENTITY_Ego *ego,
1173                 void **ctx,
1174                 const char *name)
1175 {
1176   (void) cls;
1177   (void) ctx;
1178   (void) name;
1179   get_default = NULL;
1180   if (NULL == ego)
1181   {
1182     fprintf (stderr,
1183              _("No default ego configured in identity service\n"));
1184     GNUNET_SCHEDULER_shutdown ();
1185     ret = -1;
1186     return;
1187   }
1188   else
1189   {
1190     identity_cb (cls, ego);
1191   }
1192 }
1193
1194
1195 static void
1196 id_connect_cb (void *cls,
1197                struct GNUNET_IDENTITY_Ego *ego,
1198                void **ctx,
1199                const char *name)
1200 {
1201   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1202
1203   (void) cls;
1204   (void) ctx;
1205   (void) name;
1206   if (NULL == ego)
1207   {
1208     get_default = GNUNET_IDENTITY_get (idh,
1209                                        "namestore",
1210                                        &default_ego_cb,
1211                                        (void *) cfg);
1212   }
1213 }
1214
1215
1216 /**
1217  * Main function that will be run.
1218  *
1219  * @param cls closure
1220  * @param args remaining command-line arguments
1221  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1222  * @param cfg configuration
1223  */
1224 static void
1225 run (void *cls,
1226      char *const *args,
1227      const char *cfgfile,
1228      const struct GNUNET_CONFIGURATION_Handle *cfg)
1229 {
1230   (void) cls;
1231   (void) args;
1232   (void) cfgfile;
1233   if ( (NULL != args[0]) &&
1234        (NULL == uri) )
1235     uri = GNUNET_strdup (args[0]);
1236
1237   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1238                                  (void *) cfg);
1239
1240   if (NULL == ego_name)
1241   {
1242     idh = GNUNET_IDENTITY_connect (cfg,
1243                                    &id_connect_cb,
1244                                    (void *) cfg);
1245     if (NULL == idh)
1246       fprintf (stderr,
1247                _("Cannot connect to identity service\n"));
1248     ret = -1;
1249     return;
1250   }
1251   el = GNUNET_IDENTITY_ego_lookup (cfg,
1252                                    ego_name,
1253                                    &identity_cb,
1254                                    (void *) cfg);
1255 }
1256
1257
1258 /**
1259  * The main function for gnunet-namestore.
1260  *
1261  * @param argc number of arguments from the command line
1262  * @param argv command line arguments
1263  * @return 0 ok, 1 on error
1264  */
1265 int
1266 main (int argc,
1267       char *const *argv)
1268 {
1269   struct GNUNET_GETOPT_CommandLineOption options[] = {
1270     GNUNET_GETOPT_option_flag ('a',
1271                                "add",
1272                                gettext_noop ("add record"),
1273                                &add),
1274     GNUNET_GETOPT_option_flag ('d',
1275                                "delete",
1276                                gettext_noop ("delete record"),
1277                                &del),
1278     GNUNET_GETOPT_option_flag ('D',
1279                                "display",
1280                                gettext_noop ("display records"),
1281                                &list),
1282     GNUNET_GETOPT_option_string ('e',
1283                                  "expiration",
1284                                  "TIME",
1285                                  gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"),
1286                                  &expirationstring),
1287     GNUNET_GETOPT_option_string ('i',
1288                                  "nick",
1289                                  "NICKNAME",
1290                                  gettext_noop ("set the desired nick name for the zone"),
1291                                  &nickstring),
1292     GNUNET_GETOPT_option_flag ('m',
1293                                "monitor",
1294                                gettext_noop ("monitor changes in the namestore"),
1295                                &monitor),
1296     GNUNET_GETOPT_option_string ('n',
1297                                  "name",
1298                                  "NAME",
1299                                  gettext_noop ("name of the record to add/delete/display"),
1300                                  &name),
1301     GNUNET_GETOPT_option_string ('r',
1302                                  "reverse",
1303                                  "PKEY",
1304                                  gettext_noop ("determine our name for the given PKEY"),
1305                                  &reverse_pkey),
1306     GNUNET_GETOPT_option_string ('t',
1307                                  "type",
1308                                  "TYPE",
1309                                  gettext_noop ("type of the record to add/delete/display"),
1310                                  &typestring),
1311     GNUNET_GETOPT_option_string ('u',
1312                                  "uri",
1313                                  "URI",
1314                                  gettext_noop ("URI to import into our zone"),
1315                                  &uri),
1316     GNUNET_GETOPT_option_string ('V',
1317                                  "value",
1318                                  "VALUE",
1319                                  gettext_noop ("value of the record to add/delete"),
1320                                  &value),
1321     GNUNET_GETOPT_option_flag ('p',
1322                                "public",
1323                                gettext_noop ("create or list public record"),
1324                                &is_public),
1325     GNUNET_GETOPT_option_flag ('s',
1326                                "shadow",
1327                                gettext_noop ("create shadow record (only valid if all other records of the same type have expired"),
1328                                &is_shadow),
1329     GNUNET_GETOPT_option_string ('z',
1330                                  "zone",
1331                                  "EGO",
1332                                  gettext_noop ("name of the ego controlling the zone"),
1333                                  &ego_name),
1334     GNUNET_GETOPT_OPTION_END
1335   };
1336
1337   if (GNUNET_OK !=
1338       GNUNET_STRINGS_get_utf8_args (argc, argv,
1339                                     &argc, &argv))
1340     return 2;
1341
1342   is_public = -1;
1343   is_shadow = -1;
1344   GNUNET_log_setup ("gnunet-namestore",
1345                     "WARNING",
1346                     NULL);
1347   if (GNUNET_OK !=
1348       GNUNET_PROGRAM_run (argc,
1349                           argv,
1350                           "gnunet-namestore",
1351                           _("GNUnet zone manipulation tool"),
1352                           options,
1353                           &run, NULL))
1354   {
1355     GNUNET_free ((void*) argv);
1356     GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1357     return 1;
1358   }
1359   GNUNET_free ((void*) argv);
1360   GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1361   return ret;
1362 }
1363
1364 /* end of gnunet-namestore.c */