use NULL value in load_path_suffix to NOT load any files
[oweals/gnunet.git] / src / abd / gnunet-abd.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012-2013 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 /**
21  * @file gnunet-abd.c
22  * @brief command line tool to access command line Credential service
23  * @author Martin Schanzenbach
24  */
25 #include "platform.h"
26 #include <gnunet_util_lib.h>
27 #include <gnunet_abd_service.h>
28 #include <gnunet_gnsrecord_lib.h>
29 #include <gnunet_namestore_service.h>
30 #include "delegate_misc.h"
31 #include "abd_serialization.h"
32
33 /**
34  * Configuration we are using.
35  */
36 static const struct GNUNET_CONFIGURATION_Handle *cfg;
37
38 /**
39  * Handle to the namestore.
40  */
41 static struct GNUNET_NAMESTORE_Handle *ns;
42
43 /**
44  * Private key for the our zone.
45  */
46 static struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
47
48 /**
49  * EgoLookup
50  */
51 static struct GNUNET_IDENTITY_EgoLookup *el;
52
53 /**
54  * Handle to Credential service.
55  */
56 static struct GNUNET_ABD_Handle *abd;
57
58 /**
59  * Desired timeout for the lookup (default is no timeout).
60  */
61 static struct GNUNET_TIME_Relative timeout;
62
63 /**
64  * Handle to verify request
65  */
66 static struct GNUNET_ABD_Request *verify_request;
67
68 /**
69  * Handle to collect request
70  */
71 static struct GNUNET_ABD_Request *collect_request;
72
73 /**
74  * Task scheduled to handle timeout.
75  */
76 static struct GNUNET_SCHEDULER_Task *tt;
77
78 /**
79  * Return value of the commandline.
80  */
81 static int ret = 0;
82
83 /**
84  * Subject pubkey string
85  */
86 static char *subject;
87
88 /**
89  * Subject delegate string
90  */
91 static char *subject_delegate;
92
93 /**
94  * Credential TTL
95  */
96 static char *expiration;
97
98 /**
99  * Subject key
100  */
101 struct GNUNET_CRYPTO_EcdsaPublicKey subject_pkey;
102
103 /**
104  * Issuer key
105  */
106 struct GNUNET_CRYPTO_EcdsaPublicKey issuer_pkey;
107
108
109 /**
110  * Issuer pubkey string
111  */
112 static char *issuer_key;
113
114 /**
115  * ego
116  */
117 static char *ego_name;
118
119 /**
120  * Issuer attribute
121  */
122 static char *issuer_attr;
123
124 /**
125  * Verify mode
126  */
127 static int verify;
128
129 /**
130  * Collect mode
131  */
132 static int collect;
133
134 /**
135  * Create mode
136  */
137 static int create_is;
138
139 /**
140  * Create mode
141  */
142 static int create_ss;
143
144 /**
145  * Create mode
146  */
147 static int sign_ss;
148
149 /**
150  * Signed issue credentials
151  */
152 static char *import;
153
154 /**
155  * Is record private
156  */
157 static int is_private;
158
159 /**
160  * Search direction: forward
161  */
162 static int forward;
163
164 /**
165  * Search direction: backward
166  */
167 static int backward;
168
169 /**
170  * API enum, filled and passed for collect/verify
171  */
172 enum GNUNET_ABD_AlgoDirectionFlags direction = 0;
173
174 /**
175  * Queue entry for the 'add' operation.
176  */
177 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
178
179 /**
180  * Value in binary format.
181  */
182 static void *data;
183
184 /**
185  * Number of bytes in #data.
186  */
187 static size_t data_size;
188
189 /**
190  * Type string converted to DNS type value.
191  */
192 static uint32_t type;
193
194 /**
195  * Type of the record to add/remove, NULL to remove all.
196  */
197 static char *typestring;
198 /**
199  * Expiration string converted to numeric value.
200  */
201 static uint64_t etime;
202
203 /**
204  * Is expiration time relative or absolute time?
205  */
206 static int etime_is_rel = GNUNET_SYSERR;
207
208 /**
209  * Fixed size of the public/private keys
210  */
211 static const int key_length = 52;
212
213 /**
214  * Record label for storing delegations
215  */
216 static char *record_label;
217
218 /**
219  * Task run on shutdown.  Cleans up everything.
220  *
221  * @param cls unused
222  */
223 static void
224 do_shutdown (void *cls)
225 {
226   if (NULL != verify_request)
227   {
228     GNUNET_ABD_request_cancel (verify_request);
229     verify_request = NULL;
230   }
231   if (NULL != abd)
232   {
233     GNUNET_ABD_disconnect (abd);
234     abd = NULL;
235   }
236   if (NULL != tt)
237   {
238     GNUNET_SCHEDULER_cancel (tt);
239     tt = NULL;
240   }
241   if (NULL != el)
242   {
243     GNUNET_IDENTITY_ego_lookup_cancel (el);
244     el = NULL;
245   }
246   if (NULL != add_qe)
247   {
248     GNUNET_NAMESTORE_cancel (add_qe);
249     add_qe = NULL;
250   }
251   if (NULL != ns)
252   {
253     GNUNET_NAMESTORE_disconnect (ns);
254     ns = NULL;
255   }
256 }
257
258
259 /**
260  * Task run on timeout. Triggers shutdown.
261  *
262  * @param cls unused
263  */
264 static void
265 do_timeout (void *cls)
266 {
267   tt = NULL;
268   GNUNET_SCHEDULER_shutdown ();
269 }
270
271
272 static void
273 handle_intermediate_result (void *cls,
274                             struct GNUNET_ABD_Delegation *dd,
275                             bool is_bw)
276 {
277   char *prefix = "";
278   if (is_bw)
279     prefix = "Backward -";
280   else
281     prefix = "Forward -";
282
283   printf ("%s Intermediate result: %s.%s <- %s.%s\n",
284           prefix,
285           GNUNET_CRYPTO_ecdsa_public_key_to_string (&dd->issuer_key),
286           dd->issuer_attribute,
287           GNUNET_CRYPTO_ecdsa_public_key_to_string (&dd->subject_key),
288           dd->subject_attribute);
289 }
290
291
292 static void
293 handle_collect_result (void *cls,
294                        unsigned int d_count,
295                        struct GNUNET_ABD_Delegation *dc,
296                        unsigned int c_count,
297                        struct GNUNET_ABD_Delegate *dele)
298 {
299   int i;
300   char *line;
301
302   verify_request = NULL;
303   if (NULL != dele)
304   {
305     for (i = 0; i < c_count; i++)
306     {
307       line = GNUNET_ABD_delegate_to_string (&dele[i]);
308       printf ("%s\n", line);
309       GNUNET_free (line);
310     }
311   }
312   else
313   {
314     printf ("Received NULL\n");
315   }
316
317   GNUNET_SCHEDULER_shutdown ();
318 }
319
320
321 static void
322 handle_verify_result (void *cls,
323                       unsigned int d_count,
324                       struct GNUNET_ABD_Delegation *dc,
325                       unsigned int c_count,
326                       struct GNUNET_ABD_Delegate *dele)
327 {
328   int i;
329   char *iss_key;
330   char *sub_key;
331
332   verify_request = NULL;
333   if (NULL == dele)
334     ret = 1;
335   else
336   {
337     printf ("Delegation Chain:\n");
338     for (i = 0; i < d_count; i++)
339     {
340       iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].issuer_key);
341       sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dc[i].subject_key);
342
343       if (0 != dc[i].subject_attribute_len)
344       {
345         printf ("(%d) %s.%s <- %s.%s\n",
346                 i,
347                 iss_key,
348                 dc[i].issuer_attribute,
349                 sub_key,
350                 dc[i].subject_attribute);
351       }
352       else
353       {
354         printf ("(%d) %s.%s <- %s\n",
355                 i,
356                 iss_key,
357                 dc[i].issuer_attribute,
358                 sub_key);
359       }
360       GNUNET_free (iss_key);
361       GNUNET_free (sub_key);
362     }
363     printf ("\nDelegate(s):\n");
364     for (i = 0; i < c_count; i++)
365     {
366       iss_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dele[i].issuer_key);
367       sub_key = GNUNET_CRYPTO_ecdsa_public_key_to_string (&dele[i].subject_key);
368       printf ("%s.%s <- %s\n", iss_key, dele[i].issuer_attribute, sub_key);
369       GNUNET_free (iss_key);
370       GNUNET_free (sub_key);
371     }
372     printf ("Successful.\n");
373   }
374
375   GNUNET_SCHEDULER_shutdown ();
376 }
377
378
379 /**
380  * Callback invoked from identity service with ego information.
381  * An @a ego of NULL means the ego was not found.
382  *
383  * @param cls closure with the configuration
384  * @param ego an ego known to identity service, or NULL
385  */
386 static void
387 identity_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
388 {
389   const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
390
391   el = NULL;
392   if (NULL == ego)
393   {
394     if (NULL != ego_name)
395     {
396       fprintf (stderr,
397                _ ("Ego `%s' not known to identity service\n"),
398                ego_name);
399     }
400     GNUNET_SCHEDULER_shutdown ();
401     return;
402   }
403
404   if (GNUNET_YES == collect)
405   {
406
407     if (GNUNET_OK !=
408         GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
409                                                     strlen (issuer_key),
410                                                     &issuer_pkey))
411     {
412       fprintf (stderr,
413                _ ("Issuer public key `%s' is not well-formed\n"),
414                issuer_key);
415       GNUNET_SCHEDULER_shutdown ();
416     }
417     privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
418
419     collect_request = GNUNET_ABD_collect (abd,
420                                           &issuer_pkey,
421                                           issuer_attr,
422                                           privkey,
423                                           direction,
424                                           &handle_collect_result,
425                                           NULL,
426                                           &handle_intermediate_result,
427                                           NULL);
428     return;
429   }
430   GNUNET_SCHEDULER_shutdown ();
431 }
432
433
434 /**
435  * Parse expiration time.
436  *
437  * @param expirationstring text to parse
438  * @param etime_is_rel[out] set to #GNUNET_YES if time is relative
439  * @param etime[out] set to expiration time (abs or rel)
440  * @return #GNUNET_OK on success
441  */
442 static int
443 parse_expiration (const char *expirationstring,
444                   int *etime_is_rel,
445                   uint64_t *etime)
446 {
447   // copied from namestore/gnunet-namestore.c
448   struct GNUNET_TIME_Relative etime_rel;
449   struct GNUNET_TIME_Absolute etime_abs;
450
451   if (0 == strcmp (expirationstring, "never"))
452   {
453     *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
454     *etime_is_rel = GNUNET_NO;
455     return GNUNET_OK;
456   }
457   if (GNUNET_OK ==
458       GNUNET_STRINGS_fancy_time_to_relative (expirationstring, &etime_rel))
459   {
460     *etime_is_rel = GNUNET_YES;
461     *etime = etime_rel.rel_value_us;
462     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
463                 "Storing record with relative expiration time of %s\n",
464                 GNUNET_STRINGS_relative_time_to_string (etime_rel, GNUNET_NO));
465     return GNUNET_OK;
466   }
467   if (GNUNET_OK ==
468       GNUNET_STRINGS_fancy_time_to_absolute (expirationstring, &etime_abs))
469   {
470     *etime_is_rel = GNUNET_NO;
471     *etime = etime_abs.abs_value_us;
472     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
473                 "Storing record with absolute expiration time of %s\n",
474                 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
475     return GNUNET_OK;
476   }
477   return GNUNET_SYSERR;
478 }
479
480
481 /**
482  * Function called if lookup fails.
483  */
484 static void
485 error_cb (void *cls)
486 {
487   fprintf (stderr, "Error occured during lookup, shutting down.\n");
488   GNUNET_SCHEDULER_shutdown ();
489   return;
490 }
491
492
493 static void
494 add_continuation (void *cls, int32_t success, const char *emsg)
495 {
496   struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
497   *qe = NULL;
498
499   if (GNUNET_OK == success)
500     printf ("Adding successful.\n");
501   else
502     fprintf (stderr, "Error occured during adding, shutting down.\n");
503
504   GNUNET_SCHEDULER_shutdown ();
505 }
506
507
508 static void
509 get_existing_record (void *cls,
510                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
511                      const char *rec_name,
512                      unsigned int rd_count,
513                      const struct GNUNET_GNSRECORD_Data *rd)
514 {
515   struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
516   struct GNUNET_GNSRECORD_Data *rde;
517
518   memset (rdn, 0, sizeof (struct GNUNET_GNSRECORD_Data));
519   GNUNET_memcpy (&rdn[1], rd, rd_count * sizeof (struct GNUNET_GNSRECORD_Data));
520   rde = &rdn[0];
521   rde->data = data;
522   rde->data_size = data_size;
523   rde->record_type = type;
524
525   // Set flags
526   if (GNUNET_YES == is_private)
527     rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
528   rde->expiration_time = etime;
529   if (GNUNET_YES == etime_is_rel)
530     rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
531   else if (GNUNET_NO != etime_is_rel)
532     rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
533
534   GNUNET_assert (NULL != rec_name);
535   add_qe = GNUNET_NAMESTORE_records_store (ns,
536                                            &zone_pkey,
537                                            rec_name,
538                                            rd_count + 1,
539                                            rde,
540                                            &add_continuation,
541                                            &add_qe);
542
543   return;
544 }
545
546
547 static void
548 store_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
549 {
550   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
551
552   el = NULL;
553
554   ns = GNUNET_NAMESTORE_connect (cfg);
555   if (NULL == ns)
556   {
557     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
558                 _ ("Failed to connect to namestore\n"));
559     GNUNET_SCHEDULER_shutdown ();
560     return;
561   }
562
563   // Key handling
564   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
565
566   if (GNUNET_GNSRECORD_TYPE_DELEGATE == type)
567   {
568     // Parse import
569     struct GNUNET_ABD_Delegate *cred;
570     cred = GNUNET_ABD_delegate_from_string (import);
571
572     // Get import subject public key string
573     char *subject_pubkey_str =
574       GNUNET_CRYPTO_ecdsa_public_key_to_string (&cred->subject_key);
575
576     // Get zone public key string
577     struct GNUNET_CRYPTO_EcdsaPublicKey zone_pubkey;
578     GNUNET_IDENTITY_ego_get_public_key (ego, &zone_pubkey);
579     char *zone_pubkey_str =
580       GNUNET_CRYPTO_ecdsa_public_key_to_string (&zone_pubkey);
581
582     // Check if the subject key in the signed import matches the zone's key it is issued to
583     if (strcmp (zone_pubkey_str, subject_pubkey_str) != 0)
584     {
585       fprintf (stderr,
586                "Import signed delegate does not match this ego's public key.\n");
587       GNUNET_SCHEDULER_shutdown ();
588       return;
589     }
590
591     // Expiration
592     etime = cred->expiration.abs_value_us;
593     etime_is_rel = GNUNET_NO;
594
595     // Prepare the data to be store in the record
596     data_size = GNUNET_ABD_delegate_serialize (cred, (char **) &data);
597     GNUNET_free (cred);
598   }
599   else
600   {
601     // For all other types e.g. GNUNET_GNSRECORD_TYPE_ATTRIBUTE
602     if (GNUNET_OK !=
603         GNUNET_GNSRECORD_string_to_value (type, subject, &data, &data_size))
604     {
605       fprintf (stderr,
606                "Value `%s' invalid for record type `%s'\n",
607                subject,
608                typestring);
609       GNUNET_SCHEDULER_shutdown ();
610       return;
611     }
612
613     // Take care of expiration
614     if (NULL == expiration)
615     {
616       fprintf (stderr, "Missing option -e for operation 'create'\n");
617       GNUNET_SCHEDULER_shutdown ();
618       return;
619     }
620     if (GNUNET_OK != parse_expiration (expiration, &etime_is_rel, &etime))
621     {
622       fprintf (stderr, "Invalid time format `%s'\n", expiration);
623       GNUNET_SCHEDULER_shutdown ();
624       return;
625     }
626   }
627
628   // Start lookup
629   add_qe = GNUNET_NAMESTORE_records_lookup (ns,
630                                             &zone_pkey,
631                                             record_label,
632                                             &error_cb,
633                                             NULL,
634                                             &get_existing_record,
635                                             NULL);
636   return;
637 }
638
639
640 static void
641 sign_cb (void *cls, const struct GNUNET_IDENTITY_Ego *ego)
642 {
643   const struct GNUNET_CRYPTO_EcdsaPrivateKey *privkey;
644   struct GNUNET_ABD_Delegate *dele;
645   struct GNUNET_TIME_Absolute etime_abs;
646   char *res;
647
648   el = NULL;
649
650   // work on expiration time
651   if (NULL == expiration)
652   {
653     fprintf (stderr, "Please specify a TTL\n");
654     GNUNET_SCHEDULER_shutdown ();
655     return;
656   }
657   else if (GNUNET_OK !=
658            GNUNET_STRINGS_fancy_time_to_absolute (expiration, &etime_abs))
659   {
660     fprintf (stderr,
661              "%s is not a valid ttl! Only absolute times are accepted!\n",
662              expiration);
663     GNUNET_SCHEDULER_shutdown ();
664     return;
665   }
666
667   // If contains a space - split it by the first space only - assume first entry is subject followed by attribute(s)
668   char *subject_pubkey_str;
669   char *subject_attr = NULL;
670   char *token;
671
672   // Subject Public Key
673   token = strtok (subject, " ");
674   if (key_length == strlen (token))
675   {
676     subject_pubkey_str = token;
677   }
678   else
679   {
680     fprintf (stderr, "Key error, wrong length: %ld!\n", strlen (token));
681     GNUNET_SCHEDULER_shutdown ();
682     return;
683   }
684   // Subject Attribute(s)
685   token = strtok (NULL, " ");
686   if (NULL != token)
687   {
688     subject_attr = token;
689   }
690
691   // work on keys
692   privkey = GNUNET_IDENTITY_ego_get_private_key (ego);
693
694   if (GNUNET_OK !=
695       GNUNET_CRYPTO_ecdsa_public_key_from_string (subject_pubkey_str,
696                                                   strlen (subject_pubkey_str),
697                                                   &subject_pkey))
698   {
699     fprintf (stderr,
700              "Subject public key `%s' is not well-formed\n",
701              subject_pubkey_str);
702     GNUNET_SCHEDULER_shutdown ();
703     return;
704   }
705
706   // Sign delegate
707   dele = GNUNET_ABD_delegate_issue (privkey,
708                                     &subject_pkey,
709                                     issuer_attr,
710                                     subject_attr,
711                                     &etime_abs);
712   res = GNUNET_ABD_delegate_to_string (dele);
713   GNUNET_free (dele);
714   printf ("%s\n", res);
715
716   GNUNET_free_non_null (ego_name);
717   ego_name = NULL;
718
719   GNUNET_SCHEDULER_shutdown ();
720 }
721
722
723 /**
724  * Main function that will be run.
725  *
726  * @param cls closure
727  * @param args remaining command-line arguments
728  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
729  * @param c configuration
730  */
731 static void
732 run (void *cls,
733      char *const *args,
734      const char *cfgfile,
735      const struct GNUNET_CONFIGURATION_Handle *c)
736 {
737   cfg = c;
738
739   tt = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, NULL);
740   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
741
742   // Check relevant cmdline parameters
743   if (GNUNET_YES == create_is)
744   {
745     if (NULL == ego_name)
746     {
747       fprintf (stderr, "Missing option '-ego'\n");
748       GNUNET_SCHEDULER_shutdown ();
749       return;
750     }
751     if (NULL == issuer_attr)
752     {
753       fprintf (stderr, "Missing option '-attribute' for issuer attribute\n");
754       GNUNET_SCHEDULER_shutdown ();
755       return;
756     }
757     if (NULL == subject)
758     {
759       fprintf (stderr, "Missing option -subject for operation 'create'.'\n");
760       GNUNET_SCHEDULER_shutdown ();
761       return;
762     }
763
764     // Lookup ego, on success call store_cb and store as ATTRIBUTE type
765     type = GNUNET_GNSRECORD_TYPE_ATTRIBUTE;
766     record_label = issuer_attr;
767     el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name, &store_cb, (void *) cfg);
768     return;
769   }
770
771   if (GNUNET_YES == create_ss)
772   {
773
774     // check if signed parameter has been passed in cmd line call
775     if (NULL == import)
776     {
777       fprintf (stderr, "'import' required\n");
778       GNUNET_SCHEDULER_shutdown ();
779       return;
780     }
781
782     type = GNUNET_GNSRECORD_TYPE_DELEGATE;
783     record_label = GNUNET_GNS_EMPTY_LABEL_AT;
784     // Store subject side
785     el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name, &store_cb, (void *) cfg);
786
787     return;
788   }
789
790   if (GNUNET_YES == sign_ss)
791   {
792     if (NULL == ego_name)
793     {
794       fprintf (stderr, "ego required\n");
795       GNUNET_SCHEDULER_shutdown ();
796       return;
797     }
798     if (NULL == subject)
799     {
800       fprintf (stderr, "Subject public key needed\n");
801       GNUNET_SCHEDULER_shutdown ();
802       return;
803     }
804
805     // lookup ego and call function sign_cb on success
806     el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name, &sign_cb, (void *) cfg);
807     return;
808   }
809
810   if ((GNUNET_NO == forward) && (GNUNET_NO == backward))
811   {
812     // set default: bidirectional
813     forward = GNUNET_YES;
814     backward = GNUNET_YES;
815   }
816   if (GNUNET_YES == forward)
817     direction |= GNUNET_ABD_FLAG_FORWARD;
818   if (GNUNET_YES == backward)
819     direction |= GNUNET_ABD_FLAG_BACKWARD;
820
821   if (GNUNET_YES == collect)
822   {
823     if (NULL == issuer_key)
824     {
825       fprintf (stderr, _ ("Issuer public key not well-formed\n"));
826       GNUNET_SCHEDULER_shutdown ();
827       return;
828     }
829
830     abd = GNUNET_ABD_connect (cfg);
831
832     if (NULL == abd)
833     {
834       fprintf (stderr, _ ("Failed to connect to ABD\n"));
835       GNUNET_SCHEDULER_shutdown ();
836       return;
837     }
838     if (NULL == issuer_attr)
839     {
840       fprintf (stderr, _ ("You must provide issuer the attribute\n"));
841       GNUNET_SCHEDULER_shutdown ();
842       return;
843     }
844
845     if (NULL == ego_name)
846     {
847       fprintf (stderr, _ ("ego required\n"));
848       GNUNET_SCHEDULER_shutdown ();
849       return;
850     }
851     el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name, &identity_cb, (void *) cfg);
852     return;
853   }
854
855   if (NULL == subject)
856   {
857     fprintf (stderr, _ ("Subject public key needed\n"));
858     GNUNET_SCHEDULER_shutdown ();
859     return;
860   }
861   if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (subject,
862                                                                strlen (subject),
863                                                                &subject_pkey))
864   {
865     fprintf (stderr,
866              _ ("Subject public key `%s' is not well-formed\n"),
867              subject);
868     GNUNET_SCHEDULER_shutdown ();
869     return;
870   }
871
872   if (GNUNET_YES == verify)
873   {
874     if (NULL == issuer_key)
875     {
876       fprintf (stderr, _ ("Issuer public key not well-formed\n"));
877       GNUNET_SCHEDULER_shutdown ();
878       return;
879     }
880     if (GNUNET_OK !=
881         GNUNET_CRYPTO_ecdsa_public_key_from_string (issuer_key,
882                                                     strlen (issuer_key),
883                                                     &issuer_pkey))
884     {
885       fprintf (stderr,
886                _ ("Issuer public key `%s' is not well-formed\n"),
887                issuer_key);
888       GNUNET_SCHEDULER_shutdown ();
889       return;
890     }
891     abd = GNUNET_ABD_connect (cfg);
892
893     if (NULL == abd)
894     {
895       fprintf (stderr, _ ("Failed to connect to ABD\n"));
896       GNUNET_SCHEDULER_shutdown ();
897       return;
898     }
899     if ((NULL == issuer_attr) || (NULL == subject_delegate))
900     {
901       fprintf (stderr, _ ("You must provide issuer and subject attributes\n"));
902       GNUNET_SCHEDULER_shutdown ();
903       return;
904     }
905
906     // Subject credentials are comma separated
907     char *tmp = GNUNET_strdup (subject_delegate);
908     char *tok = strtok (tmp, ",");
909     if (NULL == tok)
910     {
911       fprintf (stderr, "Invalid subject credentials\n");
912       GNUNET_free (tmp);
913       GNUNET_SCHEDULER_shutdown ();
914       return;
915     }
916     int count = 1;
917     int i;
918     while (NULL != (tok = strtok (NULL, ",")))
919       count++;
920     struct GNUNET_ABD_Delegate delegates[count];
921     struct GNUNET_ABD_Delegate *dele;
922     GNUNET_free (tmp);
923     tmp = GNUNET_strdup (subject_delegate);
924     tok = strtok (tmp, ",");
925     for (i = 0; i < count; i++)
926     {
927       dele = GNUNET_ABD_delegate_from_string (tok);
928       GNUNET_memcpy (&delegates[i],
929                      dele,
930                      sizeof (struct GNUNET_ABD_Delegate));
931       delegates[i].issuer_attribute = GNUNET_strdup (dele->issuer_attribute);
932       tok = strtok (NULL, ",");
933       GNUNET_free (dele);
934     }
935
936     verify_request = GNUNET_ABD_verify (abd,
937                                         &issuer_pkey,
938                                         issuer_attr,
939                                         &subject_pkey,
940                                         count,
941                                         delegates,
942                                         direction,
943                                         &handle_verify_result,
944                                         NULL,
945                                         &handle_intermediate_result,
946                                         NULL);
947     for (i = 0; i < count; i++)
948     {
949       GNUNET_free ((char *) delegates[i].issuer_attribute);
950     }
951     GNUNET_free (tmp);
952   }
953   else
954   {
955     fprintf (stderr,
956              _ (
957                "Please specify name to lookup, subject key and issuer key!\n"));
958     GNUNET_SCHEDULER_shutdown ();
959   }
960   return;
961 }
962
963
964 /**
965  * The main function for gnunet-gns.
966  *
967  * @param argc number of arguments from the command line
968  * @param argv command line arguments
969  * @return 0 ok, 1 on error
970  */
971 int
972 main (int argc, char *const *argv)
973 {
974   struct GNUNET_GETOPT_CommandLineOption options[] =
975   {GNUNET_GETOPT_option_flag ('V',
976                               "verify",
977                               gettext_noop (
978                                 "verify credential against attribute"),
979                               &verify),
980    GNUNET_GETOPT_option_string (
981      's',
982      "subject",
983      "PKEY",
984      gettext_noop (
985        "The public key of the subject to lookup the"
986        "credential for, or for issuer side storage: subject and its attributes"),
987      &subject),
988    GNUNET_GETOPT_option_string (
989      'd',
990      "delegate",
991      "DELE",
992      gettext_noop ("The private, signed delegate presented by the subject"),
993      &subject_delegate),
994    GNUNET_GETOPT_option_string (
995      'i',
996      "issuer",
997      "PKEY",
998      gettext_noop (
999        "The public key of the authority to verify the credential against"),
1000      &issuer_key),
1001    GNUNET_GETOPT_option_string ('e',
1002                                 "ego",
1003                                 "EGO",
1004                                 gettext_noop ("The ego/zone name to use"),
1005                                 &ego_name),
1006    GNUNET_GETOPT_option_string (
1007      'a',
1008      "attribute",
1009      "ATTR",
1010      gettext_noop ("The issuer attribute to verify against or to issue"),
1011      &issuer_attr),
1012    GNUNET_GETOPT_option_string ('T',
1013                                 "ttl",
1014                                 "EXP",
1015                                 gettext_noop (
1016                                   "The time to live for the credential."
1017                                   "e.g. 5m, 6h, \"1990-12-30 12:00:00\""),
1018                                 &expiration),
1019    GNUNET_GETOPT_option_flag ('g',
1020                               "collect",
1021                               gettext_noop ("collect credentials"),
1022                               &collect),
1023    GNUNET_GETOPT_option_flag ('U',
1024                               "createIssuerSide",
1025                               gettext_noop (
1026                                 "Create and issue a credential issuer side."),
1027                               &create_is),
1028    GNUNET_GETOPT_option_flag ('C',
1029                               "createSubjectSide",
1030                               gettext_noop (
1031                                 "Issue a credential subject side."),
1032                               &create_ss),
1033    GNUNET_GETOPT_option_flag (
1034      'S',
1035      "signSubjectSide",
1036      gettext_noop ("Create, sign and return a credential subject side."),
1037      &sign_ss),
1038    GNUNET_GETOPT_option_string (
1039      'x',
1040      "import",
1041      "IMP",
1042      gettext_noop (
1043        "Import signed credentials that should be issued to a zone/ego"),
1044      &import),
1045    GNUNET_GETOPT_option_flag ('P',
1046                               "private",
1047                               gettext_noop ("Create private record entry."),
1048                               &is_private),
1049    GNUNET_GETOPT_option_flag (
1050      'F',
1051      "forward",
1052      gettext_noop (
1053        "Indicates that the collect/verify process is done via forward search."),
1054      &forward),
1055    GNUNET_GETOPT_option_flag (
1056      'B',
1057      "backward",
1058      gettext_noop (
1059        "Indicates that the collect/verify process is done via forward search."),
1060      &backward),
1061    GNUNET_GETOPT_OPTION_END};
1062
1063
1064   timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1065   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1066     return 2;
1067
1068   GNUNET_log_setup ("gnunet-abd", "WARNING", NULL);
1069   if (GNUNET_OK != GNUNET_PROGRAM_run (argc,
1070                                        argv,
1071                                        "gnunet-abd",
1072                                        _ ("GNUnet abd resolver tool"),
1073                                        options,
1074                                        &run,
1075                                        NULL))
1076     ret = 1;
1077   GNUNET_free ((void *) argv);
1078   return ret;
1079 }
1080
1081
1082 /* end of gnunet-abd.c */