Fix last change.
[gnupg.git] / kbx / kbxutil.c
blobafc4b79e460ffc92bc4c5809ae1ad0977930840a
1 /* kbxutil.c - The Keybox utility
2 * Copyright (C) 2000, 2001, 2004, 2007 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 <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <limits.h>
29 #include <assert.h>
31 #define JNLIB_NEED_LOG_LOGV
32 #include "../jnlib/logging.h"
33 #include "../jnlib/argparse.h"
34 #include "../jnlib/stringhelp.h"
35 #include "../jnlib/utf8conv.h"
36 #include "i18n.h"
37 #include "init.h"
38 #include "keybox-defs.h"
40 #include <gcrypt.h>
42 enum cmd_and_opt_values {
43 aNull = 0,
44 oArmor = 'a',
45 oDryRun = 'n',
46 oOutput = 'o',
47 oQuiet = 'q',
48 oVerbose = 'v',
50 aNoSuchCmd = 500, /* force other values not to be a letter */
51 aFindByFpr,
52 aFindByKid,
53 aFindByUid,
54 aStats,
55 aImportOpenPGP,
56 aFindDups,
57 aCut,
59 oDebug,
60 oDebugAll,
62 oNoArmor,
63 oFrom,
64 oTo,
66 aTest
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")},
95 {0} /* end of list */
99 void myexit (int rc);
101 int keybox_errors_seen = 0;
104 static const char *
105 my_strusage( int level )
107 const char *p;
108 switch( level ) {
109 case 11: p = "kbxutil (GnuPG)";
110 break;
111 case 13: p = VERSION; break;
112 case 17: p = PRINTABLE_OS_NAME; break;
113 case 19: p =
114 _("Please report bugs to " PACKAGE_BUGREPORT ".\n");
115 break;
116 case 1:
117 case 40: p =
118 _("Usage: kbxutil [options] [files] (-h for help)");
119 break;
120 case 41: p =
121 _("Syntax: kbxutil [options] [files]\n"
122 "list, export, import Keybox data\n");
123 break;
126 default: p = NULL;
128 return p;
132 /* Used by gcry for logging */
133 static void
134 my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
136 (void)dummy;
138 /* Map the log levels. */
139 switch (level)
141 case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
142 case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
143 case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
144 case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
145 case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
146 case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
147 case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
148 default: level = JNLIB_LOG_ERROR; break;
150 log_logv (level, fmt, arg_ptr);
155 /* static void */
156 /* wrong_args( const char *text ) */
157 /* { */
158 /* log_error("usage: kbxutil %s\n", text); */
159 /* myexit ( 1 ); */
160 /* } */
163 #if 0
164 static int
165 hextobyte( const byte *s )
167 int c;
169 if( *s >= '0' && *s <= '9' )
170 c = 16 * (*s - '0');
171 else if( *s >= 'A' && *s <= 'F' )
172 c = 16 * (10 + *s - 'A');
173 else if( *s >= 'a' && *s <= 'f' )
174 c = 16 * (10 + *s - 'a');
175 else
176 return -1;
177 s++;
178 if( *s >= '0' && *s <= '9' )
179 c += *s - '0';
180 else if( *s >= 'A' && *s <= 'F' )
181 c += 10 + *s - 'A';
182 else if( *s >= 'a' && *s <= 'f' )
183 c += 10 + *s - 'a';
184 else
185 return -1;
186 return c;
188 #endif
190 #if 0
191 static char *
192 format_fingerprint ( const char *s )
194 int i, c;
195 byte fpr[20];
197 for (i=0; i < 20 && *s; ) {
198 if ( *s == ' ' || *s == '\t' ) {
199 s++;
200 continue;
202 c = hextobyte(s);
203 if (c == -1) {
204 return NULL;
206 fpr[i++] = c;
207 s += 2;
209 return gcry_xstrdup ( fpr );
211 #endif
213 #if 0
214 static int
215 format_keyid ( const char *s, u32 *kid )
217 char helpbuf[9];
218 switch ( strlen ( s ) ) {
219 case 8:
220 kid[0] = 0;
221 kid[1] = strtoul( s, NULL, 16 );
222 return 10;
224 case 16:
225 mem2str( helpbuf, s, 9 );
226 kid[0] = strtoul( helpbuf, NULL, 16 );
227 kid[1] = strtoul( s+8, NULL, 16 );
228 return 11;
230 return 0; /* error */
232 #endif
234 static char *
235 read_file (const char *fname, size_t *r_length)
237 FILE *fp;
238 char *buf;
239 size_t buflen;
241 if (!strcmp (fname, "-"))
243 size_t nread, bufsize = 0;
245 fp = stdin;
246 buf = NULL;
247 buflen = 0;
248 #define NCHUNK 8192
251 bufsize += NCHUNK;
252 if (!buf)
253 buf = xtrymalloc (bufsize);
254 else
255 buf = xtryrealloc (buf, bufsize);
256 if (!buf)
257 log_fatal ("can't allocate buffer: %s\n", strerror (errno));
259 nread = fread (buf+buflen, 1, NCHUNK, fp);
260 if (nread < NCHUNK && ferror (fp))
262 log_error ("error reading `[stdin]': %s\n", strerror (errno));
263 xfree (buf);
264 return NULL;
266 buflen += nread;
268 while (nread == NCHUNK);
269 #undef NCHUNK
272 else
274 struct stat st;
276 fp = fopen (fname, "rb");
277 if (!fp)
279 log_error ("can't open `%s': %s\n", fname, strerror (errno));
280 return NULL;
283 if (fstat (fileno(fp), &st))
285 log_error ("can't stat `%s': %s\n", fname, strerror (errno));
286 fclose (fp);
287 return NULL;
290 buflen = st.st_size;
291 buf = xtrymalloc (buflen+1);
292 if (!buf)
293 log_fatal ("can't allocate buffer: %s\n", strerror (errno));
294 if (fread (buf, buflen, 1, fp) != 1)
296 log_error ("error reading `%s': %s\n", fname, strerror (errno));
297 fclose (fp);
298 xfree (buf);
299 return NULL;
301 fclose (fp);
304 *r_length = buflen;
305 return buf;
309 static void
310 dump_fpr (const unsigned char *buffer, size_t len)
312 int i;
314 for (i=0; i < len; i++, buffer++)
316 if (len == 20)
318 if (i == 10)
319 putchar (' ');
320 printf (" %02X%02X", buffer[0], buffer[1]);
321 i++; buffer++;
323 else
325 if (i && !(i % 8))
326 putchar (' ');
327 printf (" %02X", buffer[0]);
333 static void
334 dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
336 printf ("pub %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);
340 putchar ('\n');
341 if (info->nsubkeys)
343 struct _keybox_openpgp_key_info *k;
345 k = &info->subkeys;
348 printf ("sub %02X%02X%02X%02X",
349 k->keyid[4], k->keyid[5],
350 k->keyid[6], k->keyid[7] );
351 dump_fpr (k->fpr, k->fprlen);
352 putchar ('\n');
353 k = k->next;
355 while (k);
357 if (info->nuids)
359 struct _keybox_openpgp_uid_info *u;
361 u = &info->uids;
364 printf ("uid\t\t%.*s\n", (int)u->len, image + u->off);
365 u = u->next;
367 while (u);
372 static void
373 import_openpgp (const char *filename)
375 gpg_error_t err;
376 char *buffer;
377 size_t buflen, nparsed;
378 unsigned char *p;
379 struct _keybox_openpgp_info info;
381 buffer = read_file (filename, &buflen);
382 if (!buffer)
383 return;
384 p = (unsigned char *)buffer;
385 for (;;)
387 err = _keybox_parse_openpgp (p, buflen, &nparsed, &info);
388 assert (nparsed <= buflen);
389 if (err)
391 if (gpg_err_code (err) == GPG_ERR_NO_DATA)
392 break;
393 log_info ("%s: failed to parse OpenPGP keyblock: %s\n",
394 filename, gpg_strerror (err));
396 else
398 dump_openpgp_key (&info, p);
399 _keybox_destroy_openpgp_info (&info);
401 p += nparsed;
402 buflen -= nparsed;
404 xfree (buffer);
411 main( int argc, char **argv )
413 ARGPARSE_ARGS pargs;
414 enum cmd_and_opt_values cmd = 0;
415 unsigned long from = 0, to = ULONG_MAX;
417 set_strusage( my_strusage );
418 gcry_control (GCRYCTL_DISABLE_SECMEM);
419 log_set_prefix ("kbxutil", 1);
421 /* Make sure that our subsystems are ready. */
422 init_common_subsystems ();
424 i18n_init ();
426 /* Check that the libraries are suitable. Do it here because
427 the option parsing may need services of the library. */
428 if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
430 log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
431 NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
434 gcry_set_log_handler (my_gcry_logger, NULL);
436 /*create_dotlock(NULL); register locking cleanup */
438 /* We need to use the gcry malloc function because jnlib does use them */
439 keybox_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
440 ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
443 pargs.argc = &argc;
444 pargs.argv = &argv;
445 pargs.flags= 1; /* do not remove the args */
446 while (arg_parse( &pargs, opts) )
448 switch (pargs.r_opt)
450 case oVerbose:
451 /*opt.verbose++;*/
452 /*gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose );*/
453 break;
454 case oDebug:
455 /*opt.debug |= pargs.r.ret_ulong; */
456 break;
457 case oDebugAll:
458 /*opt.debug = ~0;*/
459 break;
461 case aFindByFpr:
462 case aFindByKid:
463 case aFindByUid:
464 case aStats:
465 case aImportOpenPGP:
466 case aFindDups:
467 case aCut:
468 cmd = pargs.r_opt;
469 break;
471 case oFrom: from = pargs.r.ret_ulong; break;
472 case oTo: to = pargs.r.ret_ulong; break;
474 default:
475 pargs.err = 2;
476 break;
480 if (to < from)
481 log_error ("record number of \"--to\" is lower than \"--from\" one\n");
484 if (log_get_errorcount(0) )
485 myexit(2);
487 if (!cmd)
488 { /* Default is to list a KBX file */
489 if (!argc)
490 _keybox_dump_file (NULL, 0, stdout);
491 else
493 for (; argc; argc--, argv++)
494 _keybox_dump_file (*argv, 0, stdout);
497 else if (cmd == aStats )
499 if (!argc)
500 _keybox_dump_file (NULL, 1, stdout);
501 else
503 for (; argc; argc--, argv++)
504 _keybox_dump_file (*argv, 1, stdout);
507 else if (cmd == aFindDups )
509 if (!argc)
510 _keybox_dump_find_dups (NULL, 0, stdout);
511 else
513 for (; argc; argc--, argv++)
514 _keybox_dump_find_dups (*argv, 0, stdout);
517 else if (cmd == aCut )
519 if (!argc)
520 _keybox_dump_cut_records (NULL, from, to, stdout);
521 else
523 for (; argc; argc--, argv++)
524 _keybox_dump_cut_records (*argv, from, to, stdout);
527 else if (cmd == aImportOpenPGP)
529 if (!argc)
530 import_openpgp ("-");
531 else
533 for (; argc; argc--, argv++)
534 import_openpgp (*argv);
537 #if 0
538 else if ( cmd == aFindByFpr )
540 char *fpr;
541 if ( argc != 2 )
542 wrong_args ("kbxfile foingerprint");
543 fpr = format_fingerprint ( argv[1] );
544 if ( !fpr )
545 log_error ("invalid formatted fingerprint\n");
546 else
548 kbxfile_search_by_fpr ( argv[0], fpr );
549 gcry_free ( fpr );
552 else if ( cmd == aFindByKid )
554 u32 kid[2];
555 int mode;
557 if ( argc != 2 )
558 wrong_args ("kbxfile short-or-long-keyid");
559 mode = format_keyid ( argv[1], kid );
560 if ( !mode )
561 log_error ("invalid formatted keyID\n");
562 else
564 kbxfile_search_by_kid ( argv[0], kid, mode );
567 else if ( cmd == aFindByUid )
569 if ( argc != 2 )
570 wrong_args ("kbxfile userID");
571 kbxfile_search_by_uid ( argv[0], argv[1] );
573 #endif
574 else
575 log_error ("unsupported action\n");
577 myexit(0);
578 return 8; /*NEVER REACHED*/
582 void
583 myexit( int rc )
585 /* if( opt.debug & DBG_MEMSTAT_VALUE ) {*/
586 /* gcry_control( GCRYCTL_DUMP_MEMORY_STATS ); */
587 /* gcry_control( GCRYCTL_DUMP_RANDOM_STATS ); */
588 /* }*/
589 /* if( opt.debug ) */
590 /* gcry_control( GCRYCTL_DUMP_SECMEM_STATS ); */
591 rc = rc? rc : log_get_errorcount(0)? 2 :
592 keybox_errors_seen? 1 : 0;
593 exit(rc );