3 * $Id: keyutil.c,v 1.2 1999/10/15 21:05:28 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.2 1999/10/15 21:05:28 mdw
34 * In `key list', show timezone for local times, and support `-u' option
37 * Revision 1.1 1999/09/03 08:41:12 mdw
42 /*----- Header files ------------------------------------------------------*/
52 #include <mLib/mdwopt.h>
53 #include <mLib/quis.h>
54 #include <mLib/report.h>
63 /*----- Handy global state ------------------------------------------------*/
65 static const char *keyfile
= "keyring";
67 /*----- Useful shared functions -------------------------------------------*/
71 * Arguments: @key_file *f@ = pointer to key file block
72 * @unsigned how@ = method to open file with
76 * Use: Opens a key file and handles errors by panicking
80 static void doopen(key_file
*f
, unsigned how
)
82 if (key_open(f
, keyfile
, how
))
83 die(1, "couldn't open file `%s': %s", keyfile
, strerror(errno
));
86 /* --- @doclose@ --- *
88 * Arguments: @key_file *f@ = pointer to key file block
92 * Use: Closes a key file and handles errors by panicking
96 static void doclose(key_file
*f
)
98 switch (key_close(f
)) {
100 die(EXIT_FAILURE
, "couldn't write file `%s': %s",
101 keyfile
, strerror(errno
));
103 die(EXIT_FAILURE
, "keyring file `%s' broken: %s (repair manually)",
104 keyfile
, strerror(errno
));
108 /* --- @setattr@ --- *
110 * Arguments: @key_file *f@ = pointer to key file block
111 * @key *k@ = pointer to key block
112 * @char *v[]@ = array of assignments (overwritten!)
116 * Use: Applies the attribute assignments to the key.
119 static void setattr(key_file
*f
, key
*k
, char *v
[])
123 size_t eq
= strcspn(p
, "=");
125 moan("invalid assignment: `%s'", p
);
128 key_putattr(f
, k
, *v
, *p ? p
: 0);
133 /*----- Command implementation --------------------------------------------*/
135 /* --- @cmd_add@ --- */
137 static int cmd_add(int argc
, char *argv
[])
142 time_t exp
= KEXP_EXPIRE
;
148 /* --- Various useful flag bits --- */
154 /* --- Parse options for the subcommand --- */
157 static struct option opt
[] = {
158 { "bits", OPTF_ARGREQ
, 0, 'b' },
159 { "expire", OPTF_ARGREQ
, 0, 'e' },
160 { "comment", OPTF_ARGREQ
, 0, 'c' },
163 int i
= mdwopt(argc
, argv
, "+b:e:c:", opt
, 0, 0, 0);
167 /* --- Handle the various options --- */
171 /* --- Bits must be nonzero and a multiple of 8 --- */
174 if (!(bits
= atoi(optarg
)) || bits
% 8)
175 die(EXIT_FAILURE
, "bad number of bits: `%s'", optarg
);
178 /* --- Expiry dates get passed to @get_date@ for parsing --- */
181 if (strcmp(optarg
, "forever") == 0)
184 exp
= get_date(optarg
, 0);
186 die(EXIT_FAILURE
, "bad expiry date: `%s'", optarg
);
190 /* --- Store comments without interpretation --- */
193 if (key_chkcomment(c
))
194 die(EXIT_FAILURE
, "bad comment string: `%s'", optarg
);
198 /* --- Other things are bogus --- */
206 /* --- Various sorts of bogusity --- */
208 if (fl
& f_bogus
|| optind
+ 1 > argc
) {
210 "Usage: add [-b BITS] [-e EXPIRE] [-c COMMENT] TYPE [ATTR...]");
212 if (key_chktype(argv
[optind
]))
213 die(EXIT_FAILURE
, "bad key type: `%s'", argv
[optind
]);
214 if (exp
== KEXP_EXPIRE
)
215 exp
= time(0) + 14 * 24 * 60 * 60;
217 /* --- Initialize the Catacomb random number generator --- */
219 rand_init(RAND_GLOBAL
);
220 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
222 /* --- Extract the key data from the generator --- */
226 rand_getgood(RAND_GLOBAL
, p
, sz
);
228 /* --- Open the file, add the key, set attributes, close, return --- */
230 doopen(&f
, KOPEN_WRITE
);
231 if (!(k
= key_new(&f
, argv
[optind
], p
, sz
, exp
, c
)))
232 moan("key not added: expiry date in past?");
233 setattr(&f
, k
, argv
+ optind
+ 1);
238 /* --- @cmd_expire@ --- */
240 static int cmd_expire(int argc
, char *argv
[])
249 die(EXIT_FAILURE
, "Usage: expire KEYID...");
250 doopen(&f
, KOPEN_WRITE
);
251 for (i
= 1; i
< argc
; i
++) {
252 id
= (uint32
)strtoul(argv
[i
], 0, 16);
253 if ((k
= key_byid(&f
, id
)) != 0)
256 moan("keyid %lx not found", (unsigned long)id
);
264 /* --- @cmd_delete@ --- */
266 static int cmd_delete(int argc
, char *argv
[])
275 die(EXIT_FAILURE
, "Usage: delete KEYID...");
276 doopen(&f
, KOPEN_WRITE
);
277 for (i
= 1; i
< argc
; i
++) {
278 id
= (uint32
)strtoul(argv
[i
], 0, 16);
279 if ((k
= key_byid(&f
, id
)) != 0)
282 moan("keyid %lx not found", (unsigned long)id
);
290 /* --- @cmd_setattr@ --- */
292 static int cmd_setattr(int argc
, char *argv
[])
299 die(EXIT_FAILURE
, "Usage: setattr KEYID ATTR...");
300 doopen(&f
, KOPEN_WRITE
);
301 id
= (uint32
)strtoul(argv
[1], 0, 16);
302 if ((k
= key_byid(&f
, id
)) == 0)
303 die(EXIT_FAILURE
, "keyid %lx not found", (unsigned long)id
);
304 setattr(&f
, k
, argv
+ 2);
309 /* --- @cmd_comment@ --- */
311 static int cmd_comment(int argc
, char *argv
[])
317 if (argc
< 2 || argc
> 3)
318 die(EXIT_FAILURE
, "Usage: comment KEYID [COMMENT]");
319 doopen(&f
, KOPEN_WRITE
);
320 id
= (uint32
)strtoul(argv
[1], 0, 16);
321 if ((k
= key_byid(&f
, id
)) == 0)
322 die(EXIT_FAILURE
, "keyid %lx not found", (unsigned long)id
);
323 if (key_chkcomment(argv
[2]))
324 die(EXIT_FAILURE
, "bad comment: `%s'", argv
[2]);
325 key_setcomment(&f
, k
, argv
[2]);
330 /* --- @cmd_list@ --- */
332 static int cmd_list(int argc
, char *argv
[])
349 /* --- Parse subcommand options --- */
352 static struct option opt
[] = {
353 { "quiet", 0, 0, 'q' },
354 { "verbose", 0, 0, 'v' },
355 { "utc", 0, 0, 'u' },
358 int i
= mdwopt(argc
, argv
, "+uqv", opt
, 0, 0, 0);
379 if (fl
& f_bogus
|| optind
!= argc
)
380 die(EXIT_FAILURE
, "Usage: list [-uqv]");
382 /* --- Open the key file --- */
384 doopen(&f
, KOPEN_READ
);
387 /* --- Write the header --- */
392 tfmt
= "%Y-%m-%d %H:%M:%S UTC";
394 tfmt
= "%Y-%m-%d %H:%M:%S %Z";
396 /* --- Now iterate through the keys --- */
398 for (key_mkiter(&i
, &f
); (k
= key_next(&i
)) != 0; ) {
399 char ebuf
[24], dbuf
[24];
402 /* --- Sort out the expiry times --- */
404 if (KEY_EXPIRED(t
, k
->exp
)) {
405 strcpy(ebuf
, "expired");
406 if (KEY_DELETED(t
, k
->del
)) {
407 strcpy(dbuf
, "deleted");
413 if (k
->exp
== KEXP_FOREVER
)
414 strcpy(ebuf
, "forever");
416 tm
= (fl
& f_utc
) ?
gmtime(&k
->exp
) : localtime(&k
->exp
);
417 strftime(ebuf
, sizeof(ebuf
), tfmt
, tm
);
420 /* --- Sort out the delete times --- */
423 if (k
->del
== KEXP_UNUSED
)
424 strcpy(dbuf
, "on expiry");
425 else if (k
->del
== KEXP_FOREVER
)
426 strcpy(dbuf
, "forever");
428 tm
= localtime(&k
->del
);
429 strftime(dbuf
, sizeof(dbuf
), tfmt
, tm
);
434 /* --- Display the data obtained so far --- */
437 if (!(fl
& f_newline
)) {
438 printf("%8s %-20s %-10s %-10s %-23s\n",
439 "Id", "Type", "Expire", "Delete", "Comment");
441 printf("%08lx %-20s %-10s %-10s %-23s\n",
442 (unsigned long)k
->id
, k
->type
, ebuf
, dbuf
,
443 k
->c ? k
->c
: "<none>");
447 /* --- Display the standard header --- */
451 printf("keyid: %08lx\n", (unsigned long)k
->id
);
452 printf("type: %s\n", k
->type
);
453 printf("expiry: %s\n", ebuf
);
454 printf("delete: %s\n", dbuf
);
455 printf("comment: %s\n", k
->c ? k
->c
: "<none>");
457 /* --- Display the attributes --- */
464 printf("attributes:");
465 for (key_mkattriter(&i
, &f
, k
); key_nextattr(&i
, &an
, &av
); ) {
466 printf("\n\t%s = %s", an
, av
);
475 /* --- If dumping requested, dump the raw key data in hex --- */
478 unsigned char *p
= k
->k
;
479 unsigned char *l
= p
+ k
->ksz
;
482 fputs("key:", stdout
);
485 fputs("\n\t", stdout
);
486 else if (sz
% 8 == 0)
490 printf("%02x", *p
++);
502 /* --- @cmd_extract@ --- */
504 static int cmd_extract(int argc
, char *argv
[])
514 die(EXIT_FAILURE
, "Usage: extract FILE KEYID...");
515 if (strcmp(argv
[1], "-") == 0)
517 else if (!(fp
= fopen(argv
[1], "w"))) {
518 die(EXIT_FAILURE
, "couldn't open `%s' for writing: %s",
519 argv
[1], strerror(errno
));
522 doopen(&f
, KOPEN_WRITE
);
523 for (i
= 2; i
< argc
; i
++) {
524 id
= (uint32
)strtoul(argv
[i
], 0, 16);
525 if ((k
= key_byid(&f
, id
)) != 0)
526 key_extract(&f
, k
, fp
);
528 moan("keyid %lx not found", (unsigned long)id
);
536 /* --- @cmd_tidy@ --- */
538 static int cmd_tidy(int argc
, char *argv
[])
542 die(EXIT_FAILURE
, "usage: tidy");
543 doopen(&f
, KOPEN_WRITE
);
544 f
.f
|= KF_MODIFIED
; /* Nasty hack */
549 /* --- @cmd_merge@ --- */
551 static int cmd_merge(int argc
, char *argv
[])
557 die(EXIT_FAILURE
, "Usage: merge FILE");
558 if (strcmp(argv
[1], "-") == 0)
560 else if (!(fp
= fopen(argv
[1], "r"))) {
561 die(EXIT_FAILURE
, "couldn't open `%s' for writing: %s",
562 argv
[1], strerror(errno
));
565 doopen(&f
, KOPEN_WRITE
);
566 key_merge(&f
, argv
[1], fp
);
571 /*----- Main command table ------------------------------------------------*/
575 int (*cmd
)(int /*argc*/, char */
*argv*/
[]);
579 "add [-b BITS] [-e EXPIRE] [-c COMMENT] TYPE [ATTR...]" },
580 { "expire", cmd_expire
, "expire KEYID..." },
581 { "delete", cmd_delete
, "delete KEYID..." },
582 { "setattr", cmd_setattr
, "setattr KEYID ATTR..." },
583 { "comment", cmd_comment
, "comment KEYID [COMMENT]" },
584 { "list", cmd_list
, "list [-uqv]" },
585 { "tidy", cmd_tidy
, "tidy" },
586 { "extract", cmd_extract
, "extract FILE KEYID..." },
587 { "merge", cmd_merge
, "merge FILE" },
591 typedef struct cmd cmd
;
593 /*----- Main code ---------------------------------------------------------*/
595 /* --- Helpful GNUy functions --- */
599 fprintf(fp
, "Usage: %s [-k file] command [args]\n", QUIS
);
602 void version(FILE *fp
)
604 fprintf(fp
, "%s, Catacomb version " VERSION
"\n", QUIS
);
614 Performs various simple key management operations. Command line options\n\
617 -h, --help Display this help text.\n\
618 -v, --version Display version number.\n\
619 -u, --usage Display short usage summary.\n\
621 -k, --keyring=FILE Read and write keys in FILE.\n\
623 The following commands are understood:\n\n",
625 for (c
= cmds
; c
->name
; c
++)
626 fprintf(fp
, "%s\n", c
->help
);
631 * Arguments: @int argc@ = number of command line arguments
632 * @char *argv[]@ = array of command line arguments
634 * Returns: Nonzero on failure.
636 * Use: Main program. Performs simple key management functions.
639 int main(int argc
, char *argv
[])
647 /* --- Initialization --- */
652 /* --- Parse command line options --- */
655 static struct option opt
[] = {
657 /* --- Standard GNUy help options --- */
659 { "help", 0, 0, 'h' },
660 { "version", 0, 0, 'v' },
661 { "usage", 0, 0, 'u' },
663 /* --- Real live useful options --- */
665 { "keyring", OPTF_ARGREQ
, 0, 'k' },
667 /* --- Magic terminator --- */
671 int i
= mdwopt(argc
, argv
, "+hvu k:", opt
, 0, 0, 0);
677 /* --- GNU help options --- */
688 /* --- Real useful options --- */
694 /* --- Bogosity --- */
702 /* --- Complain about excessive bogons --- */
704 if (f
& f_bogus
|| optind
== argc
) {
709 /* --- Dispatch to appropriate command handler --- */
717 size_t sz
= strlen(argv
[0]);
719 for (c
= cmds
; c
->name
; c
++) {
720 if (strncmp(argv
[0], c
->name
, sz
) == 0) {
721 if (c
->name
[sz
] == 0) {
725 die(EXIT_FAILURE
, "ambiguous command name `%s'", argv
[0]);
731 die(EXIT_FAILURE
, "unknown command name `%s'", argv
[0]);
732 return (chosen
->cmd(argc
, argv
));
736 /*----- That's all, folks -------------------------------------------------*/