3 * $Id: keyutil.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
5 * Simple key manager program
7 * (c) 1999 Mark Wooding
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.1 1999/09/03 08:41:12 mdw
38 /*----- Header files ------------------------------------------------------*/
48 #include <mLib/mdwopt.h>
49 #include <mLib/quis.h>
50 #include <mLib/report.h>
59 /*----- Handy global state ------------------------------------------------*/
61 static const char *keyfile = "keyring";
63 /*----- Useful shared functions -------------------------------------------*/
67 * Arguments: @key_file *f@ = pointer to key file block
68 * @unsigned how@ = method to open file with
72 * Use: Opens a key file and handles errors by panicking
76 static void doopen(key_file *f, unsigned how)
78 if (key_open(f, keyfile, how))
79 die(1, "couldn't open file `%s': %s", keyfile, strerror(errno));
82 /* --- @doclose@ --- *
84 * Arguments: @key_file *f@ = pointer to key file block
88 * Use: Closes a key file and handles errors by panicking
92 static void doclose(key_file *f)
94 switch (key_close(f)) {
96 die(EXIT_FAILURE, "couldn't write file `%s': %s",
97 keyfile, strerror(errno));
99 die(EXIT_FAILURE, "keyring file `%s' broken: %s (repair manually)",
100 keyfile, strerror(errno));
104 /* --- @setattr@ --- *
106 * Arguments: @key_file *f@ = pointer to key file block
107 * @key *k@ = pointer to key block
108 * @char *v[]@ = array of assignments (overwritten!)
112 * Use: Applies the attribute assignments to the key.
115 static void setattr(key_file *f, key *k, char *v[])
119 size_t eq = strcspn(p, "=");
121 moan("invalid assignment: `%s'", p);
124 key_putattr(f, k, *v, *p ? p : 0);
129 /*----- Command implementation --------------------------------------------*/
131 /* --- @cmd_add@ --- */
133 static int cmd_add(int argc, char *argv[])
138 time_t exp = KEXP_EXPIRE;
144 /* --- Various useful flag bits --- */
150 /* --- Parse options for the subcommand --- */
153 static struct option opt[] = {
154 { "bits", OPTF_ARGREQ, 0, 'b' },
155 { "expire", OPTF_ARGREQ, 0, 'e' },
156 { "comment", OPTF_ARGREQ, 0, 'c' },
159 int i = mdwopt(argc, argv, "+b:e:c:", opt, 0, 0, 0);
163 /* --- Handle the various options --- */
167 /* --- Bits must be nonzero and a multiple of 8 --- */
170 if (!(bits = atoi(optarg)) || bits % 8)
171 die(EXIT_FAILURE, "bad number of bits: `%s'", optarg);
174 /* --- Expiry dates get passed to @get_date@ for parsing --- */
177 if (strcmp(optarg, "forever") == 0)
180 exp = get_date(optarg, 0);
182 die(EXIT_FAILURE, "bad expiry date: `%s'", optarg);
186 /* --- Store comments without interpretation --- */
189 if (key_chkcomment(c))
190 die(EXIT_FAILURE, "bad comment string: `%s'", optarg);
194 /* --- Other things are bogus --- */
202 /* --- Various sorts of bogusity --- */
204 if (fl & f_bogus || optind + 1 > argc) {
206 "Usage: add [-b BITS] [-e EXPIRE] [-c COMMENT] TYPE [ATTR...]");
208 if (key_chktype(argv[optind]))
209 die(EXIT_FAILURE, "bad key type: `%s'", argv[optind]);
210 if (exp == KEXP_EXPIRE)
211 exp = time(0) + 14 * 24 * 60 * 60;
213 /* --- Initialize the Catacomb random number generator --- */
215 rand_init(RAND_GLOBAL);
216 rand_noisesrc(RAND_GLOBAL, &noise_source);
218 /* --- Extract the key data from the generator --- */
222 rand_getgood(RAND_GLOBAL, p, sz);
224 /* --- Open the file, add the key, set attributes, close, return --- */
226 doopen(&f, KOPEN_WRITE);
227 if (!(k = key_new(&f, argv[optind], p, sz, exp, c)))
228 moan("key not added: expiry date in past?");
229 setattr(&f, k, argv + optind + 1);
234 /* --- @cmd_expire@ --- */
236 static int cmd_expire(int argc, char *argv[])
245 die(EXIT_FAILURE, "Usage: expire KEYID...");
246 doopen(&f, KOPEN_WRITE);
247 for (i = 1; i < argc; i++) {
248 id = (uint32)strtoul(argv[i], 0, 16);
249 if ((k = key_byid(&f, id)) != 0)
252 moan("keyid %lx not found", (unsigned long)id);
260 /* --- @cmd_delete@ --- */
262 static int cmd_delete(int argc, char *argv[])
271 die(EXIT_FAILURE, "Usage: delete KEYID...");
272 doopen(&f, KOPEN_WRITE);
273 for (i = 1; i < argc; i++) {
274 id = (uint32)strtoul(argv[i], 0, 16);
275 if ((k = key_byid(&f, id)) != 0)
278 moan("keyid %lx not found", (unsigned long)id);
286 /* --- @cmd_setattr@ --- */
288 static int cmd_setattr(int argc, char *argv[])
295 die(EXIT_FAILURE, "Usage: setattr KEYID ATTR...");
296 doopen(&f, KOPEN_WRITE);
297 id = (uint32)strtoul(argv[1], 0, 16);
298 if ((k = key_byid(&f, id)) == 0)
299 die(EXIT_FAILURE, "keyid %lx not found", (unsigned long)id);
300 setattr(&f, k, argv + 2);
305 /* --- @cmd_comment@ --- */
307 static int cmd_comment(int argc, char *argv[])
313 if (argc < 2 || argc > 3)
314 die(EXIT_FAILURE, "Usage: comment KEYID [COMMENT]");
315 doopen(&f, KOPEN_WRITE);
316 id = (uint32)strtoul(argv[1], 0, 16);
317 if ((k = key_byid(&f, id)) == 0)
318 die(EXIT_FAILURE, "keyid %lx not found", (unsigned long)id);
319 if (key_chkcomment(argv[2]))
320 die(EXIT_FAILURE, "bad comment: `%s'", argv[2]);
321 key_setcomment(&f, k, argv[2]);
326 /* --- @cmd_list@ --- */
328 static int cmd_list(int argc, char *argv[])
344 /* --- Parse subcommand options --- */
347 static struct option opt[] = {
348 { "quiet", 0, 0, 'q' },
349 { "verbose", 0, 0, 'v' },
352 int i = mdwopt(argc, argv, "qv", opt, 0, 0, 0);
370 if (fl & f_bogus || optind != argc)
371 die(EXIT_FAILURE, "Usage: list [-qv]");
373 /* --- Open the key file --- */
375 doopen(&f, KOPEN_READ);
378 /* --- Write the header --- */
380 tfmt = v ? "%Y-%m-%d %H:%M:%S" : "%Y-%m-%d";
382 /* --- Now iterate through the keys --- */
384 for (key_mkiter(&i, &f); (k = key_next(&i)) != 0; ) {
385 char ebuf[24], dbuf[24];
388 /* --- Sort out the expiry times --- */
390 if (KEY_EXPIRED(t, k->exp)) {
391 strcpy(ebuf, "expired");
392 if (KEY_DELETED(t, k->del)) {
393 strcpy(dbuf, "deleted");
399 if (k->exp == KEXP_FOREVER)
400 strcpy(ebuf, "forever");
402 tm = localtime(&k->exp);
403 strftime(ebuf, sizeof(ebuf), tfmt, tm);
406 /* --- Sort out the delete times --- */
409 if (k->del == KEXP_UNUSED)
410 strcpy(dbuf, "on expiry");
411 else if (k->del == KEXP_FOREVER)
412 strcpy(dbuf, "forever");
414 tm = localtime(&k->del);
415 strftime(dbuf, sizeof(dbuf), tfmt, tm);
420 /* --- Display the data obtained so far --- */
423 if (!(fl & f_newline)) {
424 printf("%8s %-20s %-10s %-10s %-23s\n",
425 "Id", "Type", "Expire", "Delete", "Comment");
427 printf("%08lx %-20s %-10s %-10s %-23s\n",
428 (unsigned long)k->id, k->type, ebuf, dbuf,
429 k->c ? k->c : "<none>");
433 /* --- Display the standard header --- */
437 printf("keyid: %08lx\n", (unsigned long)k->id);
438 printf("type: %s\n", k->type);
439 printf("expiry: %s\n", ebuf);
440 printf("delete: %s\n", dbuf);
441 printf("comment: %s\n", k->c ? k->c : "<none>");
443 /* --- Display the attributes --- */
450 printf("attributes:");
451 for (key_mkattriter(&i, &f, k); key_nextattr(&i, &an, &av); ) {
452 printf("\n\t%s = %s", an, av);
461 /* --- If dumping requested, dump the raw key data in hex --- */
464 unsigned char *p = k->k;
465 unsigned char *l = p + k->ksz;
468 fputs("key:", stdout);
471 fputs("\n\t", stdout);
472 else if (sz % 8 == 0)
476 printf("%02x", *p++);
488 /* --- @cmd_extract@ --- */
490 static int cmd_extract(int argc, char *argv[])
500 die(EXIT_FAILURE, "Usage: extract FILE KEYID...");
501 if (strcmp(argv[1], "-") == 0)
503 else if (!(fp = fopen(argv[1], "w"))) {
504 die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
505 argv[1], strerror(errno));
508 doopen(&f, KOPEN_WRITE);
509 for (i = 2; i < argc; i++) {
510 id = (uint32)strtoul(argv[i], 0, 16);
511 if ((k = key_byid(&f, id)) != 0)
512 key_extract(&f, k, fp);
514 moan("keyid %lx not found", (unsigned long)id);
522 /* --- @cmd_tidy@ --- */
524 static int cmd_tidy(int argc, char *argv[])
528 die(EXIT_FAILURE, "usage: tidy");
529 doopen(&f, KOPEN_WRITE);
530 f.f |= KF_MODIFIED; /* Nasty hack */
535 /* --- @cmd_merge@ --- */
537 static int cmd_merge(int argc, char *argv[])
543 die(EXIT_FAILURE, "Usage: merge FILE");
544 if (strcmp(argv[1], "-") == 0)
546 else if (!(fp = fopen(argv[1], "r"))) {
547 die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
548 argv[1], strerror(errno));
551 doopen(&f, KOPEN_WRITE);
552 key_merge(&f, argv[1], fp);
557 /*----- Main command table ------------------------------------------------*/
561 int (*cmd)(int /*argc*/, char */*argv*/[]);
565 "add [-b BITS] [-e EXPIRE] [-c COMMENT] TYPE [ATTR...]" },
566 { "expire", cmd_expire, "expire KEYID..." },
567 { "delete", cmd_delete, "delete KEYID..." },
568 { "setattr", cmd_setattr, "setattr KEYID ATTR..." },
569 { "comment", cmd_comment, "comment KEYID [COMMENT]" },
570 { "list", cmd_list, "list [-qv]" },
571 { "tidy", cmd_tidy, "tidy" },
572 { "extract", cmd_extract, "extract FILE KEYID..." },
573 { "merge", cmd_merge, "merge FILE" },
577 typedef struct cmd cmd;
579 /*----- Main code ---------------------------------------------------------*/
581 /* --- Helpful GNUy functions --- */
585 fprintf(fp, "Usage: %s [-k file] command [args]\n", QUIS);
588 void version(FILE *fp)
590 fprintf(fp, "%s, Catacomb version " VERSION "\n", QUIS);
600 Performs various simple key management operations. Command line options\n\
603 -h, --help Display this help text.\n\
604 -v, --version Display version number.\n\
605 -u, --usage Display short usage summary.\n\
607 -k, --keyring=FILE Read and write keys in FILE.\n\
609 The following commands are understood:\n\n",
611 for (c = cmds; c->name; c++)
612 fprintf(fp, "%s\n", c->help);
617 * Arguments: @int argc@ = number of command line arguments
618 * @char *argv[]@ = array of command line arguments
620 * Returns: Nonzero on failure.
622 * Use: Main program. Performs simple key management functions.
625 int main(int argc, char *argv[])
633 /* --- Initialization --- */
638 /* --- Parse command line options --- */
641 static struct option opt[] = {
643 /* --- Standard GNUy help options --- */
645 { "help", 0, 0, 'h' },
646 { "version", 0, 0, 'v' },
647 { "usage", 0, 0, 'u' },
649 /* --- Real live useful options --- */
651 { "keyring", OPTF_ARGREQ, 0, 'k' },
653 /* --- Magic terminator --- */
657 int i = mdwopt(argc, argv, "+hvu k:", opt, 0, 0, 0);
663 /* --- GNU help options --- */
674 /* --- Real useful options --- */
680 /* --- Bogosity --- */
688 /* --- Complain about excessive bogons --- */
690 if (f & f_bogus || optind == argc) {
695 /* --- Dispatch to appropriate command handler --- */
703 size_t sz = strlen(argv[0]);
705 for (c = cmds; c->name; c++) {
706 if (strncmp(argv[0], c->name, sz) == 0) {
707 if (c->name[sz] == 0) {
711 die(EXIT_FAILURE, "ambiguous command name `%s'", argv[0]);
717 die(EXIT_FAILURE, "unknown command name `%s'", argv[0]);
718 return (chosen->cmd(argc, argv));
722 /*----- That's all, folks -------------------------------------------------*/