1 /* kbxutil.c - The Keybox utility
2 * Copyright (C) 2000, 2001, 2004, 2007, 2011 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
31 #include <gpg-error.h>
32 #include "../common/logging.h"
33 #include "../common/argparse.h"
34 #include "../common/stringhelp.h"
35 #include "../common/utf8conv.h"
37 #include "keybox-defs.h"
38 #include "../common/init.h"
42 enum cmd_and_opt_values {
50 aNoSuchCmd = 500, /* force other values not to be a letter */
70 static ARGPARSE_OPTS opts[] = {
71 { 300, NULL, 0, N_("@Commands:\n ") },
73 /* { aFindByFpr, "find-by-fpr", 0, "|FPR| find key using it's fingerprnt" }, */
74 /* { aFindByKid, "find-by-kid", 0, "|KID| find key using it's keyid" }, */
75 /* { aFindByUid, "find-by-uid", 0, "|NAME| find key by user name" }, */
76 { aStats, "stats", 0, "show key statistics" },
77 { aImportOpenPGP, "import-openpgp", 0, "import OpenPGP keyblocks"},
78 { aFindDups, "find-dups", 0, "find duplicates" },
79 { aCut, "cut", 0, "export records" },
81 { 301, NULL, 0, N_("@\nOptions:\n ") },
83 { oFrom, "from", 4, "|N|first record to export" },
84 { oTo, "to", 4, "|N|last record to export" },
85 /* { oArmor, "armor", 0, N_("create ascii armored output")}, */
86 /* { oArmor, "armour", 0, "@" }, */
87 /* { oOutput, "output", 2, N_("use as output file")}, */
88 { oVerbose, "verbose", 0, N_("verbose") },
89 { oQuiet, "quiet", 0, N_("be somewhat more quiet") },
90 { oDryRun, "dry-run", 0, N_("do not make any changes") },
92 { oDebug, "debug" ,4|16, N_("set debugging flags")},
93 { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
101 int keybox_errors_seen = 0;
105 my_strusage( int level )
109 case 11: p = "kbxutil (@GNUPG@)";
111 case 13: p = VERSION; break;
112 case 17: p = PRINTABLE_OS_NAME; break;
113 case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
117 _("Usage: kbxutil [options] [files] (-h for help)");
120 _("Syntax: kbxutil [options] [files]\n"
121 "List, export, import Keybox data\n");
131 /* Used by gcry for logging */
133 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
137 /* Map the log levels. */
140 case GCRY_LOG_CONT: level = GPGRT_LOG_CONT; break;
141 case GCRY_LOG_INFO: level = GPGRT_LOG_INFO; break;
142 case GCRY_LOG_WARN: level = GPGRT_LOG_WARN; break;
143 case GCRY_LOG_ERROR:level = GPGRT_LOG_ERROR; break;
144 case GCRY_LOG_FATAL:level = GPGRT_LOG_FATAL; break;
145 case GCRY_LOG_BUG: level = GPGRT_LOG_BUG; break;
146 case GCRY_LOG_DEBUG:level = GPGRT_LOG_DEBUG; break;
147 default: level = GPGRT_LOG_ERROR; break;
149 log_logv (level, fmt, arg_ptr);
155 /* wrong_args( const char *text ) */
157 /* log_error("usage: kbxutil %s\n", text); */
164 hextobyte( const byte *s )
168 if( *s >= '0' && *s <= '9' )
170 else if( *s >= 'A' && *s <= 'F' )
171 c = 16 * (10 + *s - 'A');
172 else if( *s >= 'a' && *s <= 'f' )
173 c = 16 * (10 + *s - 'a');
177 if( *s >= '0' && *s <= '9' )
179 else if( *s >= 'A' && *s <= 'F' )
181 else if( *s >= 'a' && *s <= 'f' )
191 format_fingerprint ( const char *s )
196 for (i=0; i < 20 && *s; ) {
197 if ( *s == ' ' || *s == '\t' ) {
208 return gcry_xstrdup ( fpr );
214 format_keyid ( const char *s, u32 *kid )
217 switch ( strlen ( s ) ) {
220 kid[1] = strtoul( s, NULL, 16 );
224 mem2str( helpbuf, s, 9 );
225 kid[0] = strtoul( helpbuf, NULL, 16 );
226 kid[1] = strtoul( s+8, NULL, 16 );
229 return 0; /* error */
234 read_file (const char *fname, size_t *r_length)
240 if (!strcmp (fname, "-"))
242 size_t nread, bufsize = 0;
252 buf = xtrymalloc (bufsize);
254 buf = xtryrealloc (buf, bufsize);
256 log_fatal ("can't allocate buffer: %s\n", strerror (errno));
258 nread = fread (buf+buflen, 1, NCHUNK, fp);
259 if (nread < NCHUNK && ferror (fp))
261 log_error ("error reading '[stdin]': %s\n", strerror (errno));
267 while (nread == NCHUNK);
275 fp = fopen (fname, "rb");
278 log_error ("can't open '%s': %s\n", fname, strerror (errno));
282 if (fstat (fileno(fp), &st))
284 log_error ("can't stat '%s': %s\n", fname, strerror (errno));
290 buf = xtrymalloc (buflen+1);
292 log_fatal ("can't allocate buffer: %s\n", strerror (errno));
293 if (fread (buf, buflen, 1, fp) != 1)
295 log_error ("error reading '%s': %s\n", fname, strerror (errno));
309 dump_fpr (const unsigned char *buffer, size_t len)
313 for (i=0; i < len; i++, buffer++)
319 printf (" %02X%02X", buffer[0], buffer[1]);
326 printf (" %02X", buffer[0]);
333 dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
335 printf ("pub %2d %02X%02X%02X%02X",
337 info->primary.keyid[4], info->primary.keyid[5],
338 info->primary.keyid[6], info->primary.keyid[7] );
339 dump_fpr (info->primary.fpr, info->primary.fprlen);
343 struct _keybox_openpgp_key_info *k;
348 printf ("sub %2d %02X%02X%02X%02X",
350 k->keyid[4], k->keyid[5],
351 k->keyid[6], k->keyid[7] );
352 dump_fpr (k->fpr, k->fprlen);
360 struct _keybox_openpgp_uid_info *u;
365 printf ("uid\t\t%.*s\n", (int)u->len, image + u->off);
374 import_openpgp (const char *filename, int dryrun)
378 size_t buflen, nparsed;
380 struct _keybox_openpgp_info info;
383 buffer = read_file (filename, &buflen);
386 p = (unsigned char *)buffer;
389 err = _keybox_parse_openpgp (p, buflen, &nparsed, &info);
390 assert (nparsed <= buflen);
393 if (gpg_err_code (err) == GPG_ERR_NO_DATA)
395 if (gpg_err_code (err) == GPG_ERR_UNSUPPORTED_ALGORITHM)
397 /* This is likely a v3 key packet with a non-RSA
398 algorithm. These are keys from very early versions
399 of GnuPG (pre-OpenPGP). */
404 log_info ("%s: failed to parse OpenPGP keyblock: %s\n",
405 filename, gpg_strerror (err));
411 dump_openpgp_key (&info, p);
414 err = _keybox_create_openpgp_blob (&blob, &info, p, nparsed,
419 log_error ("%s: failed to create OpenPGP keyblock: %s\n",
420 filename, gpg_strerror (err));
424 err = _keybox_write_blob (blob, stdout);
425 _keybox_release_blob (blob);
429 log_error ("%s: failed to write OpenPGP keyblock: %s\n",
430 filename, gpg_strerror (err));
435 _keybox_destroy_openpgp_info (&info);
447 main( int argc, char **argv )
450 enum cmd_and_opt_values cmd = 0;
451 unsigned long from = 0, to = ULONG_MAX;
454 early_system_init ();
455 set_strusage( my_strusage );
456 gcry_control (GCRYCTL_DISABLE_SECMEM);
457 log_set_prefix ("kbxutil", GPGRT_LOG_WITH_PREFIX);
459 /* Make sure that our subsystems are ready. */
461 init_common_subsystems (&argc, &argv);
463 gcry_set_log_handler (my_gcry_logger, NULL);
465 /*create_dotlock(NULL); register locking cleanup */
467 /* We need to use the gcry malloc function because jnlib uses them. */
468 keybox_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
469 ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
474 pargs.flags= 1; /* do not remove the args */
475 while (arg_parse( &pargs, opts) )
481 /*gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose );*/
484 /*opt.debug |= pargs.r.ret_ulong; */
500 case oFrom: from = pargs.r.ret_ulong; break;
501 case oTo: to = pargs.r.ret_ulong; break;
503 case oDryRun: dry_run = 1; break;
512 log_error ("record number of \"--to\" is lower than \"--from\" one\n");
515 if (log_get_errorcount(0) )
519 { /* Default is to list a KBX file */
521 _keybox_dump_file (NULL, 0, stdout);
524 for (; argc; argc--, argv++)
525 _keybox_dump_file (*argv, 0, stdout);
528 else if (cmd == aStats )
531 _keybox_dump_file (NULL, 1, stdout);
534 for (; argc; argc--, argv++)
535 _keybox_dump_file (*argv, 1, stdout);
538 else if (cmd == aFindDups )
541 _keybox_dump_find_dups (NULL, 0, stdout);
544 for (; argc; argc--, argv++)
545 _keybox_dump_find_dups (*argv, 0, stdout);
548 else if (cmd == aCut )
551 _keybox_dump_cut_records (NULL, from, to, stdout);
554 for (; argc; argc--, argv++)
555 _keybox_dump_cut_records (*argv, from, to, stdout);
558 else if (cmd == aImportOpenPGP)
561 import_openpgp ("-", dry_run);
564 for (; argc; argc--, argv++)
565 import_openpgp (*argv, dry_run);
569 else if ( cmd == aFindByFpr )
573 wrong_args ("kbxfile foingerprint");
574 fpr = format_fingerprint ( argv[1] );
576 log_error ("invalid formatted fingerprint\n");
579 kbxfile_search_by_fpr ( argv[0], fpr );
583 else if ( cmd == aFindByKid )
589 wrong_args ("kbxfile short-or-long-keyid");
590 mode = format_keyid ( argv[1], kid );
592 log_error ("invalid formatted keyID\n");
595 kbxfile_search_by_kid ( argv[0], kid, mode );
598 else if ( cmd == aFindByUid )
601 wrong_args ("kbxfile userID");
602 kbxfile_search_by_uid ( argv[0], argv[1] );
606 log_error ("unsupported action\n");
609 return 8; /*NEVER REACHED*/
616 /* if( opt.debug & DBG_MEMSTAT_VALUE ) {*/
617 /* gcry_control( GCRYCTL_DUMP_MEMORY_STATS ); */
618 /* gcry_control( GCRYCTL_DUMP_RANDOM_STATS ); */
620 /* if( opt.debug ) */
621 /* gcry_control( GCRYCTL_DUMP_SECMEM_STATS ); */
622 rc = rc? rc : log_get_errorcount(0)? 2 :
623 keybox_errors_seen? 1 : 0;