aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/gnunet-namestore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/gnunet-namestore.c')
-rw-r--r--src/namestore/gnunet-namestore.c2120
1 files changed, 0 insertions, 2120 deletions
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c
deleted file mode 100644
index 0329c9c63..000000000
--- a/src/namestore/gnunet-namestore.c
+++ /dev/null
@@ -1,2120 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 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 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_identity_service.h>
31#include <gnunet_gnsrecord_lib.h>
32#include <gnunet_gns_service.h>
33#include <gnunet_namestore_service.h>
34#include <inttypes.h>
35
36/**
37 * The upper bound for the zone iteration interval
38 * (per record).
39 */
40#define WARN_RELATIVE_EXPIRATION_LIMIT GNUNET_TIME_relative_multiply ( \
41 GNUNET_TIME_UNIT_MINUTES, 15)
42
43/**
44 * Entry in record set for bulk processing.
45 */
46struct RecordSetEntry
47{
48 /**
49 * Kept in a linked list.
50 */
51 struct RecordSetEntry *next;
52
53 /**
54 * The record to add/remove.
55 */
56 struct GNUNET_GNSRECORD_Data record;
57};
58
59/**
60 * The record marked for deletion
61 */
62struct MarkedRecord
63{
64 /**
65 * DLL
66 */
67 struct MarkedRecord *next;
68
69 /**
70 * DLL
71 */
72 struct MarkedRecord *prev;
73
74 /**
75 * Ego Identifier
76 */
77 char *name;
78
79 /**
80 * The zone key
81 */
82 struct GNUNET_IDENTITY_PrivateKey key;
83};
84
85/**
86 * The default namestore ego
87 */
88struct EgoEntry
89{
90 /**
91 * DLL
92 */
93 struct EgoEntry *next;
94
95 /**
96 * DLL
97 */
98 struct EgoEntry *prev;
99
100 /**
101 * Ego Identifier
102 */
103 char *identifier;
104
105 /**
106 * The Ego
107 */
108 struct GNUNET_IDENTITY_Ego *ego;
109};
110
111/**
112 * Handle to the namestore.
113 */
114static struct GNUNET_NAMESTORE_Handle *ns;
115
116/**
117 * Private key for the our zone.
118 */
119static struct GNUNET_IDENTITY_PrivateKey zone_pkey;
120
121/**
122 * Identity service handle
123 */
124static struct GNUNET_IDENTITY_Handle *idh;
125
126/**
127 * Name of the ego controlling the zone.
128 */
129static char *ego_name;
130
131/**
132 * Queue entry for the 'add-uri' operation.
133 */
134static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
135
136/**
137 * Queue entry for the 'add' operation.
138 */
139static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
140
141/**
142 * Queue entry for the 'lookup' operation.
143 */
144static struct GNUNET_NAMESTORE_QueueEntry *get_qe;
145
146/**
147 * Queue entry for the 'reverse lookup' operation (in combination with a name).
148 */
149static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
150
151/**
152 * Marked record list
153 */
154static struct MarkedRecord *marked_head;
155
156/**
157 * Marked record list
158 */
159static struct MarkedRecord *marked_tail;
160
161/**
162 * Configuration handle
163 */
164const struct GNUNET_CONFIGURATION_Handle *cfg;
165
166/**
167 * Ego list
168 */
169static struct EgoEntry *ego_head;
170
171/**
172 * Ego list
173 */
174static struct EgoEntry *ego_tail;
175
176/**
177 * List iterator for the 'list' operation.
178 */
179static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
180
181/**
182 * Run in read from stdin mode.
183 */
184static int read_from_stdin;
185
186/**
187 * Desired action is to list records.
188 */
189static int list;
190
191/**
192 * Desired action is to add a record.
193 */
194static int add;
195
196/**
197 * Desired action is to remove a record.
198 */
199static int del;
200
201/**
202 * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
203 */
204static int is_public;
205
206/**
207 * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW)
208 */
209static int is_shadow;
210
211/**
212 * Filter private records
213 */
214static int omit_private;
215
216/**
217 * Output in recordline format
218 */
219static int output_recordline;
220
221
222/**
223 * Purge zone contents
224 */
225static int purge_zone;
226
227/**
228 * Do not filter maintenance records
229 */
230static int include_maintenance;
231
232/**
233 * Purge orphaned records
234 */
235static int purge_orphaned;
236
237/**
238 * List records and zone keys of orphaned records
239 */
240static int list_orphaned;
241
242/**
243 * Queue entry for the 'del' operation.
244 */
245static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
246
247/**
248 * Queue entry for the 'set/replace' operation.
249 */
250static struct GNUNET_NAMESTORE_QueueEntry *set_qe;
251
252/**
253 * Queue entry for begin/commit
254 */
255static struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
256
257/**
258 * Name of the records to add/list/remove.
259 */
260static char *name;
261
262/**
263 * Value of the record to add/remove.
264 */
265static char *value;
266
267/**
268 * URI to import.
269 */
270static char *uri;
271
272/**
273 * Reverse lookup to perform.
274 */
275static char *reverse_pkey;
276
277/**
278 * Type of the record to add/remove, NULL to remove all.
279 */
280static char *typestring;
281
282/**
283 * Desired expiration time.
284 */
285static char *expirationstring;
286
287/**
288 * Desired nick name.
289 */
290static char *nickstring;
291
292/**
293 * Global return value
294 */
295static int ret;
296
297/**
298 * Type string converted to DNS type value.
299 */
300static uint32_t type;
301
302/**
303 * Value in binary format.
304 */
305static void *data;
306
307/**
308 * Number of bytes in #data.
309 */
310static size_t data_size;
311
312/**
313 * Expiration string converted to numeric value.
314 */
315static uint64_t etime;
316
317/**
318 * Is expiration time relative or absolute time?
319 */
320static int etime_is_rel = GNUNET_SYSERR;
321
322/**
323 * Monitor handle.
324 */
325static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
326
327/**
328 * Enables monitor mode.
329 */
330static int monitor;
331
332/**
333 * Entry in record set for processing records in bulk.
334 */
335static struct RecordSetEntry *recordset;
336
337/**
338 * Purge task
339 */
340static struct GNUNET_SCHEDULER_Task *purge_task;
341
342/**
343 * Parse expiration time.
344 *
345 * @param expirationstring text to parse
346 * @param[out] etime_is_rel set to #GNUNET_YES if time is relative
347 * @param[out] etime set to expiration time (abs or rel)
348 * @return #GNUNET_OK on success
349 */
350static int
351parse_expiration (const char *expirationstring,
352 int *etime_is_rel,
353 uint64_t *etime)
354{
355 struct GNUNET_TIME_Relative etime_rel;
356 struct GNUNET_TIME_Absolute etime_abs;
357
358 if (0 == strcmp (expirationstring, "never"))
359 {
360 *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
361 *etime_is_rel = GNUNET_NO;
362 return GNUNET_OK;
363 }
364 if (GNUNET_OK ==
365 GNUNET_STRINGS_fancy_time_to_relative (expirationstring, &etime_rel))
366 {
367 *etime_is_rel = GNUNET_YES;
368 *etime = etime_rel.rel_value_us;
369 if (GNUNET_TIME_relative_cmp (etime_rel, <, WARN_RELATIVE_EXPIRATION_LIMIT))
370 {
371 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
372 "Relative expiration times of less than %s are not recommended. To improve availability, consider increasing this value.\n",
373 GNUNET_STRINGS_relative_time_to_string (
374 WARN_RELATIVE_EXPIRATION_LIMIT, GNUNET_NO));
375 }
376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
377 "Storing record with relative expiration time of %s\n",
378 GNUNET_STRINGS_relative_time_to_string (etime_rel, GNUNET_NO));
379 return GNUNET_OK;
380 }
381 if (GNUNET_OK ==
382 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring, &etime_abs))
383 {
384 *etime_is_rel = GNUNET_NO;
385 *etime = etime_abs.abs_value_us;
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387 "Storing record with absolute expiration time of %s\n",
388 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
389 return GNUNET_OK;
390 }
391 return GNUNET_SYSERR;
392}
393
394
395static int
396parse_recordline (const char *line)
397{
398 struct RecordSetEntry **head = &recordset;
399 struct RecordSetEntry *r;
400 struct GNUNET_GNSRECORD_Data record;
401 char *cp;
402 char *tok;
403 char *saveptr;
404 void *raw_data;
405
406 cp = GNUNET_strdup (line);
407 tok = strtok_r (cp, " ", &saveptr);
408 if (NULL == tok)
409 {
410 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
411 _ ("Missing entries in record line `%s'.\n"),
412 line);
413 GNUNET_free (cp);
414 return GNUNET_SYSERR;
415 }
416 record.record_type = GNUNET_GNSRECORD_typename_to_number (tok);
417 if (UINT32_MAX == record.record_type)
418 {
419 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Unknown record type `%s'\n"), tok);
420 GNUNET_free (cp);
421 return GNUNET_SYSERR;
422 }
423 tok = strtok_r (NULL, " ", &saveptr);
424 if (NULL == tok)
425 {
426 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
427 _ ("Empty record line argument is not allowed.\n"));
428 GNUNET_free (cp);
429 return GNUNET_SYSERR;
430 }
431 if (1 != sscanf (tok, "%" SCNu64, &record.expiration_time))
432 {
433 fprintf (stderr,
434 _ ("Error parsing expiration time %s.\n"), tok);
435 GNUNET_free (cp);
436 return GNUNET_SYSERR;
437 }
438 tok = strtok_r (NULL, " ", &saveptr);
439 if (NULL == tok)
440 {
441 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
442 _ ("Empty record line argument is not allowed.\n"));
443 GNUNET_free (cp);
444 return GNUNET_SYSERR;
445 }
446 record.flags = GNUNET_GNSRECORD_RF_NONE;
447 if (NULL != strchr (tok, (unsigned char) 'r'))
448 record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
449 if (NULL == strchr (tok, (unsigned char) 'p')) /* p = public */
450 record.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
451 if (NULL != strchr (tok, (unsigned char) 'S'))
452 record.flags |= GNUNET_GNSRECORD_RF_SUPPLEMENTAL;
453 if (NULL != strchr (tok, (unsigned char) 's'))
454 record.flags |= GNUNET_GNSRECORD_RF_SHADOW;
455 if (NULL != strchr (tok, (unsigned char) 'C'))
456 record.flags |= GNUNET_GNSRECORD_RF_CRITICAL;
457 tok += strlen (tok) + 1;
458 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (record.record_type,
459 tok,
460 &raw_data,
461 &record.data_size))
462 {
463 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
464 _ ("Invalid record data for type %s: `%s'.\n"),
465 GNUNET_GNSRECORD_number_to_typename (record.record_type),
466 tok);
467 GNUNET_free (cp);
468 return GNUNET_SYSERR;
469 }
470 GNUNET_free (cp);
471
472 r = GNUNET_malloc (sizeof(struct RecordSetEntry) + record.data_size);
473 r->next = *head;
474 record.data = &r[1];
475 memcpy (&r[1], raw_data, record.data_size);
476 GNUNET_free (raw_data);
477 r->record = record;
478 *head = r;
479 return GNUNET_OK;
480}
481
482static void
483reset_handles (void)
484{
485 struct MarkedRecord *mrec;
486 struct MarkedRecord *mrec_tmp;
487 struct RecordSetEntry *rs_entry;
488
489 rs_entry = recordset;
490 while (NULL != (rs_entry = recordset))
491 {
492 recordset = recordset->next;
493 GNUNET_free (rs_entry);
494 }
495 recordset = NULL;
496 if (NULL != ego_name)
497 {
498 GNUNET_free (ego_name);
499 ego_name = NULL;
500 }
501 if (NULL != name)
502 {
503 GNUNET_free (name);
504 name = NULL;
505 }
506 if (NULL != value)
507 {
508 GNUNET_free (value);
509 value = NULL;
510 }
511 if (NULL != uri)
512 {
513 GNUNET_free (uri);
514 uri = NULL;
515 }
516 if (NULL != expirationstring)
517 {
518 GNUNET_free (expirationstring);
519 expirationstring = NULL;
520 }
521 if (NULL != purge_task)
522 {
523 GNUNET_SCHEDULER_cancel (purge_task);
524 purge_task = NULL;
525 }
526 for (mrec = marked_head; NULL != mrec;)
527 {
528 mrec_tmp = mrec;
529 mrec = mrec->next;
530 GNUNET_free (mrec_tmp->name);
531 GNUNET_free (mrec_tmp);
532 }
533 if (NULL != list_it)
534 {
535 GNUNET_NAMESTORE_zone_iteration_stop (list_it);
536 list_it = NULL;
537 }
538 if (NULL != add_qe)
539 {
540 GNUNET_NAMESTORE_cancel (add_qe);
541 add_qe = NULL;
542 }
543 if (NULL != set_qe)
544 {
545 GNUNET_NAMESTORE_cancel (set_qe);
546 set_qe = NULL;
547 }
548 if (NULL != add_qe_uri)
549 {
550 GNUNET_NAMESTORE_cancel (add_qe_uri);
551 add_qe_uri = NULL;
552 }
553 if (NULL != get_qe)
554 {
555 GNUNET_NAMESTORE_cancel (get_qe);
556 get_qe = NULL;
557 }
558 if (NULL != del_qe)
559 {
560 GNUNET_NAMESTORE_cancel (del_qe);
561 del_qe = NULL;
562 }
563 if (NULL != reverse_qe)
564 {
565 GNUNET_NAMESTORE_cancel (reverse_qe);
566 reverse_qe = NULL;
567 }
568 memset (&zone_pkey, 0, sizeof(zone_pkey));
569 if (NULL != zm)
570 {
571 GNUNET_NAMESTORE_zone_monitor_stop (zm);
572 zm = NULL;
573 }
574 if (NULL != data)
575 {
576 GNUNET_free (data);
577 data = NULL;
578 }
579 if (NULL != typestring)
580 {
581 GNUNET_free (typestring);
582 typestring = NULL;
583 }
584 list = 0;
585 is_public = 0;
586 is_shadow = 0;
587 purge_zone = 0;
588}
589
590
591
592/**
593 * Task run on shutdown. Cleans up everything.
594 *
595 * @param cls unused
596 */
597static void
598do_shutdown (void *cls)
599{
600 struct EgoEntry *ego_entry;
601 struct EgoEntry *ego_tmp;
602 (void) cls;
603
604 reset_handles ();
605 if (NULL != ns_qe)
606 {
607 GNUNET_NAMESTORE_cancel (ns_qe);
608 ns_qe = NULL;
609 }
610 if (NULL != ns)
611 {
612 GNUNET_NAMESTORE_disconnect (ns);
613 ns = NULL;
614 }
615 if (NULL != idh)
616 {
617 GNUNET_IDENTITY_disconnect (idh);
618 idh = NULL;
619 }
620 for (ego_entry = ego_head; NULL != ego_entry;)
621 {
622 ego_tmp = ego_entry;
623 ego_entry = ego_entry->next;
624 GNUNET_free (ego_tmp->identifier);
625 GNUNET_free (ego_tmp);
626 }
627}
628
629static void
630commit_cb (void *cls, enum GNUNET_ErrorCode ec)
631{
632 ns_qe = NULL;
633 if (GNUNET_EC_NONE != ec)
634 {
635 fprintf (stderr, "Failed to commit to namestore: `%s'\n",
636 GNUNET_ErrorCode_get_hint (ec));
637 ret = 1;
638 }
639 GNUNET_SCHEDULER_shutdown ();
640}
641
642static void
643process_command_stdin ();
644
645
646static void
647finish_command (void)
648{
649 reset_handles ();
650 if (read_from_stdin)
651 {
652 process_command_stdin ();
653 return;
654 }
655 ns_qe = GNUNET_NAMESTORE_transaction_commit (ns, &commit_cb, NULL);
656}
657
658
659static void
660add_continuation (void *cls, enum GNUNET_ErrorCode ec)
661{
662 struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
663
664 *qe = NULL;
665 if (GNUNET_EC_NONE != ec)
666 {
667 fprintf (stderr,
668 _ ("Adding record failed: %s\n"),
669 GNUNET_ErrorCode_get_hint (ec));
670 if (GNUNET_EC_NAMESTORE_RECORD_EXISTS != ec)
671 ret = 1;
672 }
673 ret = 0;
674 finish_command ();
675}
676
677
678static void
679del_continuation (void *cls, enum GNUNET_ErrorCode ec)
680{
681 (void) cls;
682 del_qe = NULL;
683 if (GNUNET_EC_NAMESTORE_RECORD_NOT_FOUND == ec)
684 {
685 fprintf (stderr,
686 _ ("Deleting record failed: %s\n"), GNUNET_ErrorCode_get_hint (
687 ec));
688 }
689 finish_command ();
690}
691
692static void
693purge_next_record (void *cls);
694
695static void
696marked_deleted (void *cls, enum GNUNET_ErrorCode ec)
697{
698 del_qe = NULL;
699 if (GNUNET_EC_NONE != ec)
700 {
701 fprintf (stderr,
702 _ ("Deleting record failed: %s\n"),
703 GNUNET_ErrorCode_get_hint (ec));
704 }
705 purge_task = GNUNET_SCHEDULER_add_now (&purge_next_record, NULL);
706}
707
708
709static void
710purge_next_record (void *cls)
711{
712 struct MarkedRecord *mrec;
713 purge_task = NULL;
714
715 if (NULL == marked_head)
716 {
717 ret = 0;
718 finish_command ();
719 return;
720 }
721 mrec = marked_head;
722 GNUNET_CONTAINER_DLL_remove (marked_head,
723 marked_tail,
724 mrec);
725 del_qe = GNUNET_NAMESTORE_records_store (ns,
726 &mrec->key,
727 mrec->name,
728 0, NULL,
729 &marked_deleted,
730 NULL);
731 GNUNET_free (mrec->name);
732 GNUNET_free (mrec);
733}
734
735/**
736 * Function called when we are done with a zone iteration.
737 */
738static void
739zone_iteration_finished (void *cls)
740{
741 (void) cls;
742 list_it = NULL;
743 if (purge_orphaned || purge_zone)
744 {
745 purge_task = GNUNET_SCHEDULER_add_now (&purge_next_record, NULL);
746 return;
747 }
748 ret = 0;
749 finish_command ();
750}
751
752
753/**
754 * Function called when we encountered an error in a zone iteration.
755 */
756static void
757zone_iteration_error_cb (void *cls)
758{
759 (void) cls;
760 list_it = NULL;
761 fprintf (stderr, "Error iterating over zone\n");
762 ret = 1;
763 finish_command ();
764}
765
766static void
767collect_zone_records_to_purge (const struct
768 GNUNET_IDENTITY_PrivateKey *zone_key,
769 const char *rname,
770 unsigned int rd_len,
771 const struct GNUNET_GNSRECORD_Data *rd)
772{
773 struct MarkedRecord *mrec;
774
775 mrec = GNUNET_new (struct MarkedRecord);
776 mrec->key = *zone_key;
777 mrec->name = GNUNET_strdup (rname);
778 GNUNET_CONTAINER_DLL_insert (marked_head,
779 marked_tail,
780 mrec);
781}
782
783
784static void
785collect_orphans (const struct GNUNET_IDENTITY_PrivateKey *zone_key,
786 const char *rname,
787 unsigned int rd_len,
788 const struct GNUNET_GNSRECORD_Data *rd)
789{
790 struct EgoEntry *ego;
791 struct MarkedRecord *orphan;
792 int is_orphaned = 1;
793
794 for (ego = ego_head; NULL != ego; ego = ego->next)
795 {
796 if (0 == memcmp (GNUNET_IDENTITY_ego_get_private_key (ego->ego),
797 zone_key,
798 sizeof (*zone_key)))
799 {
800 is_orphaned = 0;
801 break;
802 }
803 }
804 if (is_orphaned)
805 {
806 orphan = GNUNET_new (struct MarkedRecord);
807 orphan->key = *zone_key;
808 orphan->name = GNUNET_strdup (rname);
809 GNUNET_CONTAINER_DLL_insert (marked_head,
810 marked_tail,
811 orphan);
812 }
813}
814
815/**
816 * Process a record that was stored in the namestore.
817 *
818 * @param rname name that is being mapped (at most 255 characters long)
819 * @param rd_len number of entries in @a rd array
820 * @param rd array of records with data to store
821 */
822static void
823display_record (const struct GNUNET_IDENTITY_PrivateKey *zone_key,
824 const char *rname,
825 unsigned int rd_len,
826 const struct GNUNET_GNSRECORD_Data *rd)
827{
828 const char *typestr;
829 char *s;
830 const char *ets;
831 struct GNUNET_TIME_Absolute at;
832 struct GNUNET_TIME_Relative rt;
833 struct EgoEntry *ego;
834 int have_record;
835 int is_orphaned = 1;
836 char *orphaned_str;
837
838 if ((NULL != name) && (0 != strcmp (name, rname)))
839 return;
840 have_record = GNUNET_NO;
841 for (unsigned int i = 0; i < rd_len; i++)
842 {
843 if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
844 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)))
845 continue;
846 if ((type != rd[i].record_type) && (GNUNET_GNSRECORD_TYPE_ANY != type))
847 continue;
848 have_record = GNUNET_YES;
849 break;
850 }
851 if (GNUNET_NO == have_record)
852 return;
853 for (ego = ego_head; NULL != ego; ego = ego->next)
854 {
855 if (0 == memcmp (GNUNET_IDENTITY_ego_get_private_key (ego->ego),
856 zone_key,
857 sizeof (*zone_key)))
858 {
859 is_orphaned = 0;
860 break;
861 }
862 }
863 if (list_orphaned && ! is_orphaned)
864 return;
865 if (! list_orphaned && is_orphaned)
866 return;
867 orphaned_str = GNUNET_IDENTITY_private_key_to_string (zone_key);
868 fprintf (stdout, "%s.%s:\n", rname, is_orphaned ? orphaned_str :
869 ego->identifier);
870 GNUNET_free (orphaned_str);
871 if (NULL != typestring)
872 type = GNUNET_GNSRECORD_typename_to_number (typestring);
873 else
874 type = GNUNET_GNSRECORD_TYPE_ANY;
875 for (unsigned int i = 0; i < rd_len; i++)
876 {
877 if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
878 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)))
879 continue;
880 if ((type != rd[i].record_type) && (GNUNET_GNSRECORD_TYPE_ANY != type))
881 continue;
882 typestr = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
883 s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
884 rd[i].data,
885 rd[i].data_size);
886 if (NULL == s)
887 {
888 fprintf (stdout,
889 _ ("\tCorrupt or unsupported record of type %u\n"),
890 (unsigned int) rd[i].record_type);
891 continue;
892 }
893 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
894 {
895 rt.rel_value_us = rd[i].expiration_time;
896 ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
897 }
898 else
899 {
900 at.abs_value_us = rd[i].expiration_time;
901 ets = GNUNET_STRINGS_absolute_time_to_string (at);
902 }
903 char flgstr[16];
904 sprintf (flgstr, "[%s%s%s%s%s]",
905 (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE) ? "" : "p",
906 (rd[i].flags & GNUNET_GNSRECORD_RF_SUPPLEMENTAL) ? "S" : "",
907 (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION) ? "r" : "",
908 (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW) ? "S" : "",
909 (rd[i].flags & GNUNET_GNSRECORD_RF_CRITICAL) ? "C" : "");
910 if (output_recordline)
911 fprintf (stdout,
912 " %s %" PRIu64 " %s %s\n",
913 typestr,
914 rd[i].expiration_time,
915 flgstr,
916 s);
917 else
918 fprintf (stdout,
919 "\t%s: %s (%s)\t%s\t%s\n",
920 typestr,
921 s,
922 ets,
923 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE"
924 : "PUBLIC",
925 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW)) ? "SHADOW"
926 : "");
927 GNUNET_free (s);
928 }
929 // fprintf (stdout, "%s", "\n");
930}
931
932static void
933purge_zone_iterator (void *cls,
934 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
935 const char *rname,
936 unsigned int rd_len,
937 const struct GNUNET_GNSRECORD_Data *rd,
938 struct GNUNET_TIME_Absolute expiry)
939{
940 (void) cls;
941 (void) zone_key;
942 (void) expiry;
943 collect_zone_records_to_purge (zone_key, rname, rd_len, rd);
944 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
945}
946
947
948static void
949purge_orphans_iterator (void *cls,
950 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
951 const char *rname,
952 unsigned int rd_len,
953 const struct GNUNET_GNSRECORD_Data *rd,
954 struct GNUNET_TIME_Absolute expiry)
955{
956 (void) cls;
957 (void) zone_key;
958 (void) expiry;
959 collect_orphans (zone_key, rname, rd_len, rd);
960 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
961}
962
963
964/**
965 * Process a record that was stored in the namestore.
966 *
967 * @param cls closure
968 * @param zone_key private key of the zone
969 * @param rname name that is being mapped (at most 255 characters long)
970 * @param rd_len number of entries in @a rd array
971 * @param rd array of records with data to store
972 */
973static void
974display_record_iterator (void *cls,
975 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
976 const char *rname,
977 unsigned int rd_len,
978 const struct GNUNET_GNSRECORD_Data *rd,
979 struct GNUNET_TIME_Absolute expiry)
980{
981 (void) cls;
982 (void) zone_key;
983 (void) expiry;
984 display_record (zone_key, rname, rd_len, rd);
985 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
986}
987
988
989/**
990 * Process a record that was stored in the namestore.
991 *
992 * @param cls closure
993 * @param zone_key private key of the zone
994 * @param rname name that is being mapped (at most 255 characters long)
995 * @param rd_len number of entries in @a rd array
996 * @param rd array of records with data to store
997 */
998static void
999display_record_monitor (void *cls,
1000 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
1001 const char *rname,
1002 unsigned int rd_len,
1003 const struct GNUNET_GNSRECORD_Data *rd,
1004 struct GNUNET_TIME_Absolute expiry)
1005{
1006 (void) cls;
1007 (void) zone_key;
1008 (void) expiry;
1009 display_record (zone_key, rname, rd_len, rd);
1010 GNUNET_NAMESTORE_zone_monitor_next (zm, 1);
1011}
1012
1013
1014/**
1015 * Process a record that was stored in the namestore.
1016 *
1017 * @param cls closure
1018 * @param zone_key private key of the zone
1019 * @param rname name that is being mapped (at most 255 characters long)
1020 * @param rd_len number of entries in @a rd array
1021 * @param rd array of records with data to store
1022 */
1023static void
1024display_record_lookup (void *cls,
1025 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
1026 const char *rname,
1027 unsigned int rd_len,
1028 const struct GNUNET_GNSRECORD_Data *rd)
1029{
1030 (void) cls;
1031 (void) zone_key;
1032 get_qe = NULL;
1033 display_record (zone_key, rname, rd_len, rd);
1034 finish_command ();
1035}
1036
1037
1038/**
1039 * Function called once we are in sync in monitor mode.
1040 *
1041 * @param cls NULL
1042 */
1043static void
1044sync_cb (void *cls)
1045{
1046 (void) cls;
1047 fprintf (stdout, "%s", "Monitor is now in sync.\n");
1048}
1049
1050
1051/**
1052 * Function called on errors while monitoring.
1053 *
1054 * @param cls NULL
1055 */
1056static void
1057monitor_error_cb (void *cls)
1058{
1059 (void) cls;
1060 fprintf (stderr, "%s", "Monitor disconnected and out of sync.\n");
1061}
1062
1063
1064/**
1065 * Function called on errors while monitoring.
1066 *
1067 * @param cls NULL
1068 */
1069static void
1070lookup_error_cb (void *cls)
1071{
1072 (void) cls;
1073 get_qe = NULL;
1074 fprintf (stderr, "%s", "Failed to lookup record.\n");
1075 finish_command ();
1076}
1077
1078
1079/**
1080 * Function called if lookup fails.
1081 */
1082static void
1083add_error_cb (void *cls)
1084{
1085 (void) cls;
1086 add_qe = NULL;
1087 GNUNET_break (0);
1088 ret = 1;
1089 finish_command ();
1090}
1091
1092
1093/**
1094 * We're storing a record; this function is given the existing record
1095 * so that we can merge the information.
1096 *
1097 * @param cls closure, unused
1098 * @param zone_key private key of the zone
1099 * @param rec_name name that is being mapped (at most 255 characters long)
1100 * @param rd_count number of entries in @a rd array
1101 * @param rd array of records with data to store
1102 */
1103static void
1104get_existing_record (void *cls,
1105 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
1106 const char *rec_name,
1107 unsigned int rd_count,
1108 const struct GNUNET_GNSRECORD_Data *rd)
1109{
1110 struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
1111 struct GNUNET_GNSRECORD_Data *rde;
1112
1113 (void) cls;
1114 (void) zone_key;
1115 add_qe = NULL;
1116 if (0 != strcmp (rec_name, name))
1117 {
1118 GNUNET_break (0);
1119 ret = 1;
1120 finish_command ();
1121 return;
1122 }
1123
1124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125 "Received %u records for name `%s'\n",
1126 rd_count,
1127 rec_name);
1128 for (unsigned int i = 0; i < rd_count; i++)
1129 {
1130 switch (rd[i].record_type)
1131 {
1132 case GNUNET_DNSPARSER_TYPE_SOA:
1133 if (GNUNET_DNSPARSER_TYPE_SOA == type)
1134 {
1135 fprintf (
1136 stderr,
1137 _ (
1138 "A SOA record exists already under `%s', cannot add a second SOA to the same zone.\n"),
1139 rec_name);
1140 ret = 1;
1141 finish_command ();
1142 return;
1143 }
1144 break;
1145 }
1146 }
1147 memset (rdn, 0, sizeof(struct GNUNET_GNSRECORD_Data));
1148 GNUNET_memcpy (&rdn[1], rd, rd_count * sizeof(struct GNUNET_GNSRECORD_Data));
1149 rde = &rdn[0];
1150 rde->data = data;
1151 rde->data_size = data_size;
1152 rde->record_type = type;
1153 if (1 == is_shadow)
1154 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW;
1155 if (1 != is_public)
1156 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1157 rde->expiration_time = etime;
1158 if (GNUNET_YES == etime_is_rel)
1159 rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1160 else if (GNUNET_NO != etime_is_rel)
1161 rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
1162 GNUNET_assert (NULL != name);
1163 add_qe = GNUNET_NAMESTORE_records_store (ns,
1164 &zone_pkey,
1165 name,
1166 rd_count + 1,
1167 rde,
1168 &add_continuation,
1169 &add_qe);
1170}
1171
1172
1173/**
1174 * Function called if we encountered an error in zone-to-name.
1175 */
1176static void
1177reverse_error_cb (void *cls)
1178{
1179 (void) cls;
1180 reverse_qe = NULL;
1181 fprintf (stdout, "%s.zkey\n", reverse_pkey);
1182}
1183
1184
1185/**
1186 * Function called with the result of our attempt to obtain a name for a given
1187 * public key.
1188 *
1189 * @param cls NULL
1190 * @param zone private key of the zone; NULL on disconnect
1191 * @param label label of the records; NULL on disconnect
1192 * @param rd_count number of entries in @a rd array, 0 if label was deleted
1193 * @param rd array of records with data to store
1194 */
1195static void
1196handle_reverse_lookup (void *cls,
1197 const struct GNUNET_IDENTITY_PrivateKey *zone,
1198 const char *label,
1199 unsigned int rd_count,
1200 const struct GNUNET_GNSRECORD_Data *rd)
1201{
1202 (void) cls;
1203 (void) zone;
1204 (void) rd_count;
1205 (void) rd;
1206 reverse_qe = NULL;
1207 if (NULL == label)
1208 fprintf (stdout, "%s\n", reverse_pkey);
1209 else
1210 fprintf (stdout, "%s.%s\n", label, ego_name);
1211 finish_command ();
1212}
1213
1214
1215/**
1216 * Function called if lookup for deletion fails.
1217 */
1218static void
1219del_lookup_error_cb (void *cls)
1220{
1221 (void) cls;
1222 del_qe = NULL;
1223 GNUNET_break (0);
1224 ret = 1;
1225 finish_command ();
1226}
1227
1228
1229/**
1230 * We were asked to delete something; this function is called with
1231 * the existing records. Now we should determine what should be
1232 * deleted and then issue the deletion operation.
1233 *
1234 * @param cls NULL
1235 * @param zone private key of the zone we are deleting from
1236 * @param label name of the records we are editing
1237 * @param rd_count size of the @a rd array
1238 * @param rd existing records
1239 */
1240static void
1241del_monitor (void *cls,
1242 const struct GNUNET_IDENTITY_PrivateKey *zone,
1243 const char *label,
1244 unsigned int rd_count,
1245 const struct GNUNET_GNSRECORD_Data *rd)
1246{
1247 struct GNUNET_GNSRECORD_Data rdx[rd_count];
1248 unsigned int rd_left;
1249 uint32_t type;
1250 char *vs;
1251
1252 (void) cls;
1253 (void) zone;
1254 del_qe = NULL;
1255 if (0 == rd_count)
1256 {
1257 fprintf (stderr,
1258 _ (
1259 "There are no records under label `%s' that could be deleted.\n"),
1260 label);
1261 ret = 1;
1262 finish_command ();
1263 return;
1264 }
1265 if ((NULL == value) && (NULL == typestring))
1266 {
1267 /* delete everything */
1268 del_qe = GNUNET_NAMESTORE_records_store (ns,
1269 &zone_pkey,
1270 name,
1271 0,
1272 NULL,
1273 &del_continuation,
1274 NULL);
1275 return;
1276 }
1277 rd_left = 0;
1278 if (NULL != typestring)
1279 type = GNUNET_GNSRECORD_typename_to_number (typestring);
1280 else
1281 type = GNUNET_GNSRECORD_TYPE_ANY;
1282 for (unsigned int i = 0; i < rd_count; i++)
1283 {
1284 vs = NULL;
1285 if (! (((GNUNET_GNSRECORD_TYPE_ANY == type) ||
1286 (rd[i].record_type == type)) &&
1287 ((NULL == value) ||
1288 (NULL ==
1289 (vs = (GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
1290 rd[i].data,
1291 rd[i].data_size)))) ||
1292 (0 == strcmp (vs, value)))))
1293 rdx[rd_left++] = rd[i];
1294 GNUNET_free (vs);
1295 }
1296 if (rd_count == rd_left)
1297 {
1298 /* nothing got deleted */
1299 fprintf (
1300 stderr,
1301 _ (
1302 "There are no records under label `%s' that match the request for deletion.\n"),
1303 label);
1304 finish_command ();
1305 return;
1306 }
1307 /* delete everything but what we copied to 'rdx' */
1308 del_qe = GNUNET_NAMESTORE_records_store (ns,
1309 &zone_pkey,
1310 name,
1311 rd_left,
1312 rdx,
1313 &del_continuation,
1314 NULL);
1315}
1316
1317
1318static void
1319replace_cont (void *cls, enum GNUNET_ErrorCode ec)
1320{
1321 (void) cls;
1322
1323 set_qe = NULL;
1324 if (GNUNET_EC_NONE != ec)
1325 {
1326 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1327 _ ("%s\n"),
1328 GNUNET_ErrorCode_get_hint (ec));
1329 ret = 1; /* fail from 'main' */
1330 }
1331 finish_command ();
1332}
1333
1334
1335/**
1336 * We have obtained the zone's private key, so now process
1337 * the main commands using it.
1338 *
1339 * @param cfg configuration to use
1340 */
1341static void
1342run_with_zone_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg)
1343{
1344 struct GNUNET_GNSRECORD_Data rd;
1345 enum GNUNET_GNSRECORD_Filter filter_flags = GNUNET_GNSRECORD_FILTER_NONE;
1346
1347 if (omit_private)
1348 filter_flags |= GNUNET_GNSRECORD_FILTER_OMIT_PRIVATE;
1349 if (include_maintenance)
1350 filter_flags |= GNUNET_GNSRECORD_FILTER_INCLUDE_MAINTENANCE;
1351 if (! (add | del | list | (NULL != nickstring) | (NULL != uri)
1352 | (NULL != reverse_pkey) | (NULL != recordset) | (monitor)
1353 | (purge_orphaned) | (list_orphaned) | (purge_zone)) )
1354 {
1355 /* nothing more to be done */
1356 fprintf (stderr, _ ("No options given\n"));
1357 finish_command ();
1358 return;
1359 }
1360
1361 if (NULL != recordset)
1362 {
1363 /* replace entire record set */
1364 unsigned int rd_count;
1365 struct GNUNET_GNSRECORD_Data *rd;
1366
1367 /* FIXME: We could easily support append and delete with this as well */
1368 if (! add)
1369 {
1370 fprintf (stderr, _ ("Recordlines only work with option `%s'\n"),
1371 "-a");
1372 ret = 1;
1373 finish_command ();
1374 return;
1375 }
1376 if (NULL == name)
1377 {
1378 fprintf (stderr,
1379 _ ("Missing option `%s' for operation `%s'\n"),
1380 "-n",
1381 _ ("name"));
1382 ret = 1;
1383 finish_command ();
1384 return;
1385 }
1386 rd_count = 0;
1387 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1388 rd_count++;
1389 rd = GNUNET_new_array (rd_count, struct GNUNET_GNSRECORD_Data);
1390 rd_count = 0;
1391 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1392 {
1393 rd[rd_count] = e->record;
1394 rd_count++;
1395 }
1396 set_qe = GNUNET_NAMESTORE_records_store (ns,
1397 &zone_pkey,
1398 name,
1399 rd_count,
1400 rd,
1401 &replace_cont,
1402 NULL);
1403 GNUNET_free (rd);
1404 return;
1405 }
1406 if (NULL != nickstring)
1407 {
1408 if (0 == strlen (nickstring))
1409 {
1410 fprintf (stderr, _ ("Invalid nick `%s'\n"), nickstring);
1411 ret = 1;
1412 finish_command ();
1413 return;
1414 }
1415 add = 1;
1416 typestring = GNUNET_strdup (GNUNET_GNSRECORD_number_to_typename (
1417 GNUNET_GNSRECORD_TYPE_NICK));
1418 name = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
1419 value = GNUNET_strdup (nickstring);
1420 is_public = 0;
1421 expirationstring = GNUNET_strdup ("never");
1422 GNUNET_free (nickstring);
1423 nickstring = NULL;
1424 }
1425
1426 if (add)
1427 {
1428 if (NULL == ego_name)
1429 {
1430 fprintf (stderr,
1431 _ ("Missing option `%s' for operation `%s'\n"),
1432 "-z",
1433 _ ("add"));
1434 ret = 1;
1435 finish_command ();
1436 return;
1437 }
1438 if (NULL == name)
1439 {
1440 fprintf (stderr,
1441 _ ("Missing option `%s' for operation `%s'\n"),
1442 "-n",
1443 _ ("add"));
1444 ret = 1;
1445 finish_command ();
1446 return;
1447 }
1448 if (NULL == typestring)
1449 {
1450 fprintf (stderr,
1451 _ ("Missing option `%s' for operation `%s'\n"),
1452 "-t",
1453 _ ("add"));
1454 ret = 1;
1455 finish_command ();
1456 return;
1457 }
1458 type = GNUNET_GNSRECORD_typename_to_number (typestring);
1459 if (UINT32_MAX == type)
1460 {
1461 fprintf (stderr, _ ("Unsupported type `%s'\n"), typestring);
1462 ret = 1;
1463 finish_command ();
1464 return;
1465 }
1466 if ((GNUNET_DNSPARSER_TYPE_SRV == type) ||
1467 (GNUNET_DNSPARSER_TYPE_TLSA == type) ||
1468 (GNUNET_DNSPARSER_TYPE_OPENPGPKEY == type))
1469 {
1470 fprintf (stderr,
1471 _ ("For DNS record types `SRV', `TLSA' and `OPENPGPKEY'"));
1472 fprintf (stderr, ", please use a `BOX' record instead\n");
1473 ret = 1;
1474 finish_command ();
1475 return;
1476 }
1477 if (NULL == value)
1478 {
1479 fprintf (stderr,
1480 _ ("Missing option `%s' for operation `%s'\n"),
1481 "-V",
1482 _ ("add"));
1483 ret = 1;
1484 finish_command ();
1485 return;
1486 }
1487 if (GNUNET_OK !=
1488 GNUNET_GNSRECORD_string_to_value (type, value, &data, &data_size))
1489 {
1490 fprintf (stderr,
1491 _ ("Value `%s' invalid for record type `%s'\n"),
1492 value,
1493 typestring);
1494 ret = 1;
1495 finish_command ();
1496 return;
1497 }
1498 if (NULL == expirationstring)
1499 {
1500 fprintf (stderr,
1501 _ ("Missing option `%s' for operation `%s'\n"),
1502 "-e",
1503 _ ("add"));
1504 ret = 1;
1505 finish_command ();
1506 return;
1507 }
1508 if (GNUNET_OK != parse_expiration (expirationstring, &etime_is_rel, &etime))
1509 {
1510 fprintf (stderr, _ ("Invalid time format `%s'\n"), expirationstring);
1511 ret = 1;
1512 finish_command ();
1513 return;
1514 }
1515 add_qe = GNUNET_NAMESTORE_records_lookup (ns,
1516 &zone_pkey,
1517 name,
1518 &add_error_cb,
1519 NULL,
1520 &get_existing_record,
1521 NULL);
1522 }
1523 if (del)
1524 {
1525 if (NULL == ego_name)
1526 {
1527 fprintf (stderr,
1528 _ ("Missing option `%s' for operation `%s'\n"),
1529 "-z",
1530 _ ("del"));
1531 ret = 1;
1532 finish_command ();
1533 return;
1534 }
1535 if (NULL == name)
1536 {
1537 fprintf (stderr,
1538 _ ("Missing option `%s' for operation `%s'\n"),
1539 "-n",
1540 _ ("del"));
1541 ret = 1;
1542 finish_command ();
1543 return;
1544 }
1545 del_qe = GNUNET_NAMESTORE_records_lookup (ns,
1546 &zone_pkey,
1547 name,
1548 &del_lookup_error_cb,
1549 NULL,
1550 &del_monitor,
1551 NULL);
1552 }
1553 if (purge_orphaned)
1554 {
1555 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1556 NULL,
1557 &zone_iteration_error_cb,
1558 NULL,
1559 &purge_orphans_iterator,
1560 NULL,
1561 &zone_iteration_finished,
1562 NULL,
1563 filter_flags);
1564
1565 }
1566 else if (purge_zone)
1567 {
1568 if (NULL == ego_name)
1569 {
1570 fprintf (stderr,
1571 _ ("Missing option `%s' for operation `%s'\n"),
1572 "-z",
1573 _ ("purge-zone"));
1574 ret = 1;
1575 finish_command ();
1576 return;
1577 }
1578 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1579 &zone_pkey,
1580 &zone_iteration_error_cb,
1581 NULL,
1582 &purge_zone_iterator,
1583 NULL,
1584 &zone_iteration_finished,
1585 NULL,
1586 filter_flags);
1587
1588 }
1589 else if (list || list_orphaned)
1590 {
1591 if (NULL != name)
1592 {
1593 if (NULL == ego_name)
1594 {
1595 fprintf (stderr,
1596 _ ("Missing option `%s' for operation `%s'\n"),
1597 "-z",
1598 _ ("list"));
1599 ret = 1;
1600 finish_command ();
1601 return;
1602 }
1603 get_qe = GNUNET_NAMESTORE_records_lookup (ns,
1604 &zone_pkey,
1605 name,
1606 &lookup_error_cb,
1607 NULL,
1608 &display_record_lookup,
1609 NULL);
1610 }
1611 else
1612 list_it = GNUNET_NAMESTORE_zone_iteration_start2 (ns,
1613 (NULL == ego_name) ?
1614 NULL : &zone_pkey,
1615 &zone_iteration_error_cb,
1616 NULL,
1617 &display_record_iterator,
1618 NULL,
1619 &zone_iteration_finished,
1620 NULL,
1621 filter_flags);
1622 }
1623 if (NULL != reverse_pkey)
1624 {
1625 struct GNUNET_IDENTITY_PublicKey pubkey;
1626
1627 if (NULL == ego_name)
1628 {
1629 fprintf (stderr,
1630 _ ("Missing option `%s' for operation `%s'\n"),
1631 "-z",
1632 _ ("reverse-pkey"));
1633 ret = 1;
1634 finish_command ();
1635 return;
1636 }
1637 if (GNUNET_OK !=
1638 GNUNET_IDENTITY_public_key_from_string (reverse_pkey,
1639 &pubkey))
1640 {
1641 fprintf (stderr,
1642 _ ("Invalid public key for reverse lookup `%s'\n"),
1643 reverse_pkey);
1644 ret = 1;
1645 finish_command ();
1646 return;
1647 }
1648 reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
1649 &zone_pkey,
1650 &pubkey,
1651 &reverse_error_cb,
1652 NULL,
1653 &handle_reverse_lookup,
1654 NULL);
1655 }
1656 if (NULL != uri)
1657 {
1658 char sh[105];
1659 char sname[64];
1660 struct GNUNET_IDENTITY_PublicKey pkey;
1661 if (NULL == ego_name)
1662 {
1663 fprintf (stderr,
1664 _ ("Missing option `%s' for operation `%s'\n"),
1665 "-z",
1666 _ ("uri"));
1667 ret = 1;
1668 finish_command ();
1669 return;
1670 }
1671
1672 memset (sh, 0, 105);
1673 memset (sname, 0, 64);
1674
1675 if ((2 != (sscanf (uri, "gnunet://gns/%58s/%63s", sh, sname))) ||
1676 (GNUNET_OK !=
1677 GNUNET_IDENTITY_public_key_from_string (sh, &pkey)))
1678 {
1679 fprintf (stderr, _ ("Invalid URI `%s'\n"), uri);
1680 ret = 1;
1681 finish_command ();
1682 return;
1683 }
1684 if (NULL == expirationstring)
1685 {
1686 fprintf (stderr,
1687 _ ("Missing option `%s' for operation `%s'\n"),
1688 "-e",
1689 _ ("add"));
1690 ret = 1;
1691 finish_command ();
1692 return;
1693 }
1694 if (GNUNET_OK != parse_expiration (expirationstring, &etime_is_rel, &etime))
1695 {
1696 fprintf (stderr, _ ("Invalid time format `%s'\n"), expirationstring);
1697 ret = 1;
1698 finish_command ();
1699 return;
1700 }
1701 memset (&rd, 0, sizeof(rd));
1702 rd.data = &pkey;
1703 rd.data_size = GNUNET_IDENTITY_public_key_get_length (&pkey);
1704 rd.record_type = ntohl (pkey.type);
1705 rd.expiration_time = etime;
1706 if (GNUNET_YES == etime_is_rel)
1707 rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1708 if (1 == is_shadow)
1709 rd.flags |= GNUNET_GNSRECORD_RF_SHADOW;
1710 add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
1711 &zone_pkey,
1712 sname,
1713 1,
1714 &rd,
1715 &add_continuation,
1716 &add_qe_uri);
1717 }
1718 if (monitor)
1719 {
1720 zm = GNUNET_NAMESTORE_zone_monitor_start2 (cfg,
1721 (NULL != ego_name) ?
1722 &zone_pkey : NULL,
1723 GNUNET_YES,
1724 &monitor_error_cb,
1725 NULL,
1726 &display_record_monitor,
1727 NULL,
1728 &sync_cb,
1729 NULL,
1730 filter_flags);
1731 }
1732}
1733
1734#define MAX_LINE_LEN 4086
1735
1736#define MAX_ARGS 20
1737
1738static int
1739get_identity_for_string (const char *str,
1740 struct GNUNET_IDENTITY_PrivateKey *zk)
1741{
1742 const struct GNUNET_IDENTITY_PrivateKey *privkey;
1743 struct GNUNET_IDENTITY_PublicKey pubkey;
1744 struct GNUNET_IDENTITY_PublicKey ego_pubkey;
1745 struct EgoEntry *ego_entry;
1746
1747 if (GNUNET_OK == GNUNET_IDENTITY_public_key_from_string (str,
1748 &pubkey))
1749 {
1750 for (ego_entry = ego_head;
1751 NULL != ego_entry; ego_entry = ego_entry->next)
1752 {
1753 privkey = GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1754 GNUNET_IDENTITY_ego_get_public_key (ego_entry->ego, &ego_pubkey);
1755 if (0 == memcmp (&ego_pubkey, &pubkey, sizeof (pubkey)))
1756 {
1757 *zk = *privkey;
1758 return GNUNET_OK;
1759 }
1760 }
1761 }
1762 else
1763 {
1764 for (ego_entry = ego_head; NULL != ego_entry; ego_entry = ego_entry->next)
1765 {
1766 /** FIXME: Check for zTLD? **/
1767 if (0 != strcmp (str, ego_entry->identifier))
1768 continue;
1769 *zk = *GNUNET_IDENTITY_ego_get_private_key (ego_entry->ego);
1770 return GNUNET_OK;
1771 }
1772 }
1773 return GNUNET_NO;
1774}
1775
1776static void
1777process_command_stdin ()
1778{
1779 char buf[MAX_LINE_LEN];
1780 static struct GNUNET_IDENTITY_PrivateKey next_zone_key;
1781 static char next_name[GNUNET_DNSPARSER_MAX_NAME_LENGTH];
1782 static int finished = GNUNET_NO;
1783 static int have_next_zonekey = GNUNET_NO;
1784 int zonekey_set = GNUNET_NO;
1785 char *tmp;
1786
1787
1788 if (GNUNET_YES == have_next_zonekey)
1789 {
1790 zone_pkey = next_zone_key;
1791 if (NULL != name)
1792 GNUNET_free (name);
1793 name = GNUNET_strdup (next_name);
1794 zonekey_set = GNUNET_YES;
1795 }
1796 while (NULL != fgets (buf, sizeof (buf), stdin))
1797 {
1798 if (1 >= strlen (buf))
1799 continue;
1800 if (buf[strlen (buf) - 1] == '\n')
1801 buf[strlen (buf) - 1] = '\0';
1802 /**
1803 * Check if this is a new name. If yes, and we have records, store them.
1804 */
1805 if (buf[strlen (buf) - 1] == ':')
1806 {
1807 memset (next_name, 0, sizeof (next_name));
1808 strncpy (next_name, buf, strlen (buf) - 1);
1809 tmp = strchr (next_name, '.');
1810 if (NULL == tmp)
1811 {
1812 fprintf (stderr, "Error parsing name `%s'\n", next_name);
1813 ns_qe = GNUNET_NAMESTORE_transaction_commit (ns, &commit_cb, NULL);
1814 ret = 1;
1815 return;
1816 }
1817 if (GNUNET_OK != get_identity_for_string (tmp + 1, &next_zone_key))
1818 {
1819 fprintf (stderr, "Error parsing zone name `%s'\n", tmp + 1);
1820 ret = 1;
1821 GNUNET_SCHEDULER_shutdown ();
1822 return;
1823 }
1824 *tmp = '\0';
1825 have_next_zonekey = GNUNET_YES;
1826 /* Run a command for the previous record set */
1827 if (NULL != recordset)
1828 {
1829 run_with_zone_pkey (cfg);
1830 return;
1831 }
1832 zone_pkey = next_zone_key;
1833 if (NULL != name)
1834 GNUNET_free (name);
1835 name = GNUNET_strdup (next_name);
1836 zonekey_set = GNUNET_YES;
1837 continue;
1838 }
1839 if (GNUNET_NO == zonekey_set)
1840 {
1841 fprintf (stderr, "Warning, encountered recordline without zone\n");
1842 continue;
1843 }
1844 parse_recordline (buf);
1845 }
1846 if (GNUNET_NO == finished)
1847 {
1848 if (NULL != recordset)
1849 {
1850 if (GNUNET_YES == zonekey_set)
1851 {
1852 run_with_zone_pkey (cfg); /** one last time **/
1853 finished = GNUNET_YES;
1854 return;
1855 }
1856 fprintf (stderr, "Warning, encountered recordline without zone\n");
1857 }
1858 }
1859 ns_qe = GNUNET_NAMESTORE_transaction_commit (ns, &commit_cb, NULL);
1860 return;
1861}
1862
1863
1864static void
1865begin_cb (void *cls, enum GNUNET_ErrorCode ec)
1866{
1867 ns_qe = NULL;
1868 if (GNUNET_EC_NONE != ec)
1869 {
1870 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1871 "Failed to start transaction: %s\n",
1872 GNUNET_ErrorCode_get_hint (ec));
1873 GNUNET_SCHEDULER_shutdown ();
1874 return;
1875 }
1876 if (read_from_stdin)
1877 {
1878 process_command_stdin ();
1879 return;
1880 }
1881 run_with_zone_pkey (cfg);
1882}
1883
1884
1885/**
1886 * Function called with ALL of the egos known to the
1887 * identity service, used on startup if the user did
1888 * not specify a zone on the command-line.
1889 * Once the iteration is done (@a ego is NULL), we
1890 * ask for the default ego for "namestore".
1891 *
1892 * @param cls a `struct GNUNET_CONFIGURATION_Handle`
1893 * @param ego an ego, NULL for end of iteration
1894 * @param ctx NULL
1895 * @param name name associated with @a ego
1896 */
1897static void
1898id_connect_cb (void *cls,
1899 struct GNUNET_IDENTITY_Ego *ego,
1900 void **ctx,
1901 const char *name)
1902{
1903 struct GNUNET_IDENTITY_PublicKey pk;
1904 struct EgoEntry *ego_entry;
1905
1906 (void) ctx;
1907 (void) name;
1908 if ((NULL != name) && (NULL != ego))
1909 {
1910 ego_entry = GNUNET_new (struct EgoEntry);
1911 GNUNET_IDENTITY_ego_get_public_key (ego, &pk);
1912 ego_entry->ego = ego;
1913 ego_entry->identifier = GNUNET_strdup (name);
1914 GNUNET_CONTAINER_DLL_insert_tail (ego_head,
1915 ego_tail,
1916 ego_entry);
1917 if ((NULL != ego_name) &&
1918 (0 == strcmp (name, ego_name)))
1919 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1920 return;
1921 }
1922 if (NULL != ego)
1923 return;
1924 ns_qe = GNUNET_NAMESTORE_transaction_begin (ns, &begin_cb, (void *) cfg);
1925}
1926
1927
1928
1929
1930
1931/**
1932 * Main function that will be run.
1933 *
1934 * @param cls closure
1935 * @param args remaining command-line arguments
1936 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1937 * @param cfg configuration
1938 */
1939static void
1940run (void *cls,
1941 char *const *args,
1942 const char *cfgfile,
1943 const struct GNUNET_CONFIGURATION_Handle *_cfg)
1944{
1945 (void) cls;
1946 (void) args;
1947 (void) cfgfile;
1948 cfg = _cfg;
1949 if (NULL != args[0])
1950 GNUNET_log (
1951 GNUNET_ERROR_TYPE_WARNING,
1952 _ ("Superfluous command line arguments (starting with `%s') ignored\n"),
1953 args[0]);
1954
1955 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, (void *) cfg);
1956 ns = GNUNET_NAMESTORE_connect (cfg);
1957 if (NULL == ns)
1958 {
1959 fprintf (stderr, _ ("Failed to connect to namestore\n"));
1960 GNUNET_SCHEDULER_shutdown ();
1961 return;
1962 }
1963 idh = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, (void *) cfg);
1964 if (NULL == idh)
1965 {
1966 ret = -1;
1967 fprintf (stderr, _ ("Cannot connect to identity service\n"));
1968 GNUNET_SCHEDULER_shutdown ();
1969 }
1970}
1971
1972
1973
1974/**
1975 * The main function for gnunet-namestore.
1976 *
1977 * @param argc number of arguments from the command line
1978 * @param argv command line arguments
1979 * @return 0 ok, 1 on error
1980 */
1981int
1982main (int argc, char *const *argv)
1983{
1984 int lret;
1985 struct GNUNET_GETOPT_CommandLineOption options[] =
1986 { GNUNET_GETOPT_option_flag ('a', "add", gettext_noop ("add record"), &add),
1987 GNUNET_GETOPT_option_flag ('d',
1988 "delete",
1989 gettext_noop ("delete record"),
1990 &del),
1991 GNUNET_GETOPT_option_flag ('D',
1992 "display",
1993 gettext_noop ("display records"),
1994 &list),
1995 GNUNET_GETOPT_option_flag ('S',
1996 "from-stdin",
1997 gettext_noop ("read commands from stdin"),
1998 &read_from_stdin),
1999 GNUNET_GETOPT_option_string (
2000 'e',
2001 "expiration",
2002 "TIME",
2003 gettext_noop (
2004 "expiration time for record to use (for adding only), \"never\" is possible"),
2005 &expirationstring),
2006 GNUNET_GETOPT_option_string ('i',
2007 "nick",
2008 "NICKNAME",
2009 gettext_noop (
2010 "set the desired nick name for the zone"),
2011 &nickstring),
2012 GNUNET_GETOPT_option_flag ('m',
2013 "monitor",
2014 gettext_noop (
2015 "monitor changes in the namestore"),
2016 &monitor),
2017 GNUNET_GETOPT_option_string ('n',
2018 "name",
2019 "NAME",
2020 gettext_noop (
2021 "name of the record to add/delete/display"),
2022 &name),
2023 GNUNET_GETOPT_option_flag ('r',
2024 "recordline",
2025 gettext_noop ("Output in recordline format"),
2026 &output_recordline),
2027 GNUNET_GETOPT_option_string ('Z',
2028 "zone-to-name",
2029 "KEY",
2030 gettext_noop (
2031 "determine our name for the given KEY"),
2032 &reverse_pkey),
2033 GNUNET_GETOPT_option_string ('t',
2034 "type",
2035 "TYPE",
2036 gettext_noop (
2037 "type of the record to add/delete/display"),
2038 &typestring),
2039 GNUNET_GETOPT_option_string ('u',
2040 "uri",
2041 "URI",
2042 gettext_noop ("URI to import into our zone"),
2043 &uri),
2044 GNUNET_GETOPT_option_string ('V',
2045 "value",
2046 "VALUE",
2047 gettext_noop (
2048 "value of the record to add/delete"),
2049 &value),
2050 GNUNET_GETOPT_option_flag ('p',
2051 "public",
2052 gettext_noop ("create or list public record"),
2053 &is_public),
2054 GNUNET_GETOPT_option_flag ('o',
2055 "omit-private",
2056 gettext_noop ("omit private records"),
2057 &omit_private),
2058 GNUNET_GETOPT_option_flag ('T',
2059 "include-maintenance",
2060 gettext_noop (
2061 "do not filter maintenance records"),
2062 &include_maintenance),
2063 GNUNET_GETOPT_option_flag ('P',
2064 "purge-orphans",
2065 gettext_noop (
2066 "purge namestore of all orphans"),
2067 &purge_orphaned),
2068 GNUNET_GETOPT_option_flag ('O',
2069 "list-orphans",
2070 gettext_noop (
2071 "show private key for orphaned records for recovery using `gnunet-identity -C -P <key>'. Use in combination with --display"),
2072 &list_orphaned),
2073 GNUNET_GETOPT_option_flag ('X',
2074 "purge-zone-records",
2075 gettext_noop (
2076 "delete all records in specified zone"),
2077 &purge_zone),
2078 GNUNET_GETOPT_option_flag (
2079 's',
2080 "shadow",
2081 gettext_noop (
2082 "create shadow record (only valid if all other records of the same type have expired"),
2083 &is_shadow),
2084 GNUNET_GETOPT_option_string ('z',
2085 "zone",
2086 "EGO",
2087 gettext_noop (
2088 "name of the ego controlling the zone"),
2089 &ego_name),
2090 GNUNET_GETOPT_OPTION_END };
2091
2092
2093 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
2094 return 2;
2095
2096 is_public = -1;
2097 is_shadow = -1;
2098 GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
2099 if (GNUNET_OK !=
2100 (lret = GNUNET_PROGRAM_run (argc,
2101 argv,
2102 "gnunet-namestore",
2103 _ ("GNUnet zone manipulation tool"),
2104 options,
2105 &run,
2106 NULL)))
2107 {
2108 GNUNET_free_nz ((void *) argv);
2109 // FIXME
2110 // GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
2111 return lret;
2112 }
2113 GNUNET_free_nz ((void *) argv);
2114 // FIXME
2115 // GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
2116 return ret;
2117}
2118
2119
2120/* end of gnunet-namestore.c */