3 * $Id: keyutil.c,v 1.3 1999/11/02 15:23:24 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.3 1999/11/02 15:23:24 mdw
34 * Fix newlines in keyring list.
36 * Revision 1.2 1999/10/15 21:05:28 mdw
37 * In `key list', show timezone for local times, and support `-u' option
40 * Revision 1.1 1999/09/03 08:41:12 mdw
45 /*----- Header files ------------------------------------------------------*/
55 #include <mLib/mdwopt.h>
56 #include <mLib/quis.h>
57 #include <mLib/report.h>
66 /*----- Handy global state ------------------------------------------------*/
68 static const char *keyfile
= "keyring";
70 /*----- Useful shared functions -------------------------------------------*/
74 * Arguments: @key_file *f@ = pointer to key file block
75 * @unsigned how@ = method to open file with
79 * Use: Opens a key file and handles errors by panicking
83 static void doopen(key_file
*f
, unsigned how
)
85 if (key_open(f
, keyfile
, how
))
86 die(1, "couldn't open file `%s': %s", keyfile
, strerror(errno
));
89 /* --- @doclose@ --- *
91 * Arguments: @key_file *f@ = pointer to key file block
95 * Use: Closes a key file and handles errors by panicking
99 static void doclose(key_file
*f
)
101 switch (key_close(f
)) {
103 die(EXIT_FAILURE
, "couldn't write file `%s': %s",
104 keyfile
, strerror(errno
));
106 die(EXIT_FAILURE
, "keyring file `%s' broken: %s (repair manually)",
107 keyfile
, strerror(errno
));
111 /* --- @setattr@ --- *
113 * Arguments: @key_file *f@ = pointer to key file block
114 * @key *k@ = pointer to key block
115 * @char *v[]@ = array of assignments (overwritten!)
119 * Use: Applies the attribute assignments to the key.
122 static void setattr(key_file
*f
, key
*k
, char *v
[])
126 size_t eq
= strcspn(p
, "=");
128 moan("invalid assignment: `%s'", p
);
131 key_putattr(f
, k
, *v
, *p ? p
: 0);
136 /*----- Command implementation --------------------------------------------*/
138 /* --- @cmd_add@ --- */
140 static int cmd_add(int argc
, char *argv
[])
145 time_t exp
= KEXP_EXPIRE
;
151 /* --- Various useful flag bits --- */
157 /* --- Parse options for the subcommand --- */
160 static struct option opt
[] = {
161 { "bits", OPTF_ARGREQ
, 0, 'b' },
162 { "expire", OPTF_ARGREQ
, 0, 'e' },
163 { "comment", OPTF_ARGREQ
, 0, 'c' },
166 int i
= mdwopt(argc
, argv
, "+b:e:c:", opt
, 0, 0, 0);
170 /* --- Handle the various options --- */
174 /* --- Bits must be nonzero and a multiple of 8 --- */
177 if (!(bits
= atoi(optarg
)) || bits
% 8)
178 die(EXIT_FAILURE
, "bad number of bits: `%s'", optarg
);
181 /* --- Expiry dates get passed to @get_date@ for parsing --- */
184 if (strcmp(optarg
, "forever") == 0)
187 exp
= get_date(optarg
, 0);
189 die(EXIT_FAILURE
, "bad expiry date: `%s'", optarg
);
193 /* --- Store comments without interpretation --- */
196 if (key_chkcomment(c
))
197 die(EXIT_FAILURE
, "bad comment string: `%s'", optarg
);
201 /* --- Other things are bogus --- */
209 /* --- Various sorts of bogusity --- */
211 if (fl
& f_bogus
|| optind
+ 1 > argc
) {
213 "Usage: add [-b BITS] [-e EXPIRE] [-c COMMENT] TYPE [ATTR...]");
215 if (key_chktype(argv
[optind
]))
216 die(EXIT_FAILURE
, "bad key type: `%s'", argv
[optind
]);
217 if (exp
== KEXP_EXPIRE
)
218 exp
= time(0) + 14 * 24 * 60 * 60;
220 /* --- Initialize the Catacomb random number generator --- */
222 rand_init(RAND_GLOBAL
);
223 rand_noisesrc(RAND_GLOBAL
, &noise_source
);
225 /* --- Extract the key data from the generator --- */
229 rand_getgood(RAND_GLOBAL
, p
, sz
);
231 /* --- Open the file, add the key, set attributes, close, return --- */
233 doopen(&f
, KOPEN_WRITE
);
234 if (!(k
= key_new(&f
, argv
[optind
], p
, sz
, exp
, c
)))
235 moan("key not added: expiry date in past?");
236 setattr(&f
, k
, argv
+ optind
+ 1);
241 /* --- @cmd_expire@ --- */
243 static int cmd_expire(int argc
, char *argv
[])
252 die(EXIT_FAILURE
, "Usage: expire KEYID...");
253 doopen(&f
, KOPEN_WRITE
);
254 for (i
= 1; i
< argc
; i
++) {
255 id
= (uint32
)strtoul(argv
[i
], 0, 16);
256 if ((k
= key_byid(&f
, id
)) != 0)
259 moan("keyid %lx not found", (unsigned long)id
);
267 /* --- @cmd_delete@ --- */
269 static int cmd_delete(int argc
, char *argv
[])
278 die(EXIT_FAILURE
, "Usage: delete KEYID...");
279 doopen(&f
, KOPEN_WRITE
);
280 for (i
= 1; i
< argc
; i
++) {
281 id
= (uint32
)strtoul(argv
[i
], 0, 16);
282 if ((k
= key_byid(&f
, id
)) != 0)
285 moan("keyid %lx not found", (unsigned long)id
);
293 /* --- @cmd_setattr@ --- */
295 static int cmd_setattr(int argc
, char *argv
[])
302 die(EXIT_FAILURE
, "Usage: setattr KEYID ATTR...");
303 doopen(&f
, KOPEN_WRITE
);
304 id
= (uint32
)strtoul(argv
[1], 0, 16);
305 if ((k
= key_byid(&f
, id
)) == 0)
306 die(EXIT_FAILURE
, "keyid %lx not found", (unsigned long)id
);
307 setattr(&f
, k
, argv
+ 2);
312 /* --- @cmd_comment@ --- */
314 static int cmd_comment(int argc
, char *argv
[])
320 if (argc
< 2 || argc
> 3)
321 die(EXIT_FAILURE
, "Usage: comment KEYID [COMMENT]");
322 doopen(&f
, KOPEN_WRITE
);
323 id
= (uint32
)strtoul(argv
[1], 0, 16);
324 if ((k
= key_byid(&f
, id
)) == 0)
325 die(EXIT_FAILURE
, "keyid %lx not found", (unsigned long)id
);
326 if (key_chkcomment(argv
[2]))
327 die(EXIT_FAILURE
, "bad comment: `%s'", argv
[2]);
328 key_setcomment(&f
, k
, argv
[2]);
333 /* --- @cmd_list@ --- */
335 static int cmd_list(int argc
, char *argv
[])
352 /* --- Parse subcommand options --- */
355 static struct option opt
[] = {
356 { "quiet", 0, 0, 'q' },
357 { "verbose", 0, 0, 'v' },
358 { "utc", 0, 0, 'u' },
361 int i
= mdwopt(argc
, argv
, "+uqv", opt
, 0, 0, 0);
382 if (fl
& f_bogus
|| optind
!= argc
)
383 die(EXIT_FAILURE
, "Usage: list [-uqv]");
385 /* --- Open the key file --- */
387 doopen(&f
, KOPEN_READ
);
390 /* --- Write the header --- */
395 tfmt
= "%Y-%m-%d %H:%M:%S UTC";
397 tfmt
= "%Y-%m-%d %H:%M:%S %Z";
399 /* --- Now iterate through the keys --- */
401 for (key_mkiter(&i
, &f
); (k
= key_next(&i
)) != 0; ) {
402 char ebuf
[24], dbuf
[24];
405 /* --- Sort out the expiry times --- */
407 if (KEY_EXPIRED(t
, k
->exp
)) {
408 strcpy(ebuf
, "expired");
409 if (KEY_DELETED(t
, k
->del
)) {
410 strcpy(dbuf
, "deleted");
416 if (k
->exp
== KEXP_FOREVER
)
417 strcpy(ebuf
, "forever");
419 tm
= (fl
& f_utc
) ?
gmtime(&k
->exp
) : localtime(&k
->exp
);
420 strftime(ebuf
, sizeof(ebuf
), tfmt
, tm
);
423 /* --- Sort out the delete times --- */
426 if (k
->del
== KEXP_UNUSED
)
427 strcpy(dbuf
, "on expiry");
428 else if (k
->del
== KEXP_FOREVER
)
429 strcpy(dbuf
, "forever");
431 tm
= localtime(&k
->del
);
432 strftime(dbuf
, sizeof(dbuf
), tfmt
, tm
);
437 /* --- Display the data obtained so far --- */
440 if (!(fl
& f_newline
)) {
441 printf("%8s %-20s %-10s %-10s %-23s\n",
442 "Id", "Type", "Expire", "Delete", "Comment");
444 printf("%08lx %-20s %-10s %-10s %-23s\n",
445 (unsigned long)k
->id
, k
->type
, ebuf
, dbuf
,
446 k
->c ? k
->c
: "<none>");
450 /* --- Display the standard header --- */
454 printf("keyid: %08lx\n", (unsigned long)k
->id
);
455 printf("type: %s\n", k
->type
);
456 printf("expiry: %s\n", ebuf
);
457 printf("delete: %s\n", dbuf
);
458 printf("comment: %s\n", k
->c ? k
->c
: "<none>");
460 /* --- Display the attributes --- */
467 printf("attributes:");
468 for (key_mkattriter(&i
, &f
, k
); key_nextattr(&i
, &an
, &av
); ) {
469 printf("\n\t%s = %s", an
, av
);
478 /* --- If dumping requested, dump the raw key data in hex --- */
481 unsigned char *p
= k
->k
;
482 unsigned char *l
= p
+ k
->ksz
;
485 fputs("key:", stdout
);
488 fputs("\n\t", stdout
);
489 else if (sz
% 8 == 0)
493 printf("%02x", *p
++);
506 /* --- @cmd_extract@ --- */
508 static int cmd_extract(int argc
, char *argv
[])
518 die(EXIT_FAILURE
, "Usage: extract FILE KEYID...");
519 if (strcmp(argv
[1], "-") == 0)
521 else if (!(fp
= fopen(argv
[1], "w"))) {
522 die(EXIT_FAILURE
, "couldn't open `%s' for writing: %s",
523 argv
[1], strerror(errno
));
526 doopen(&f
, KOPEN_WRITE
);
527 for (i
= 2; i
< argc
; i
++) {
528 id
= (uint32
)strtoul(argv
[i
], 0, 16);
529 if ((k
= key_byid(&f
, id
)) != 0)
530 key_extract(&f
, k
, fp
);
532 moan("keyid %lx not found", (unsigned long)id
);
540 /* --- @cmd_tidy@ --- */
542 static int cmd_tidy(int argc
, char *argv
[])
546 die(EXIT_FAILURE
, "usage: tidy");
547 doopen(&f
, KOPEN_WRITE
);
548 f
.f
|= KF_MODIFIED
; /* Nasty hack */
553 /* --- @cmd_merge@ --- */
555 static int cmd_merge(int argc
, char *argv
[])
561 die(EXIT_FAILURE
, "Usage: merge FILE");
562 if (strcmp(argv
[1], "-") == 0)
564 else if (!(fp
= fopen(argv
[1], "r"))) {
565 die(EXIT_FAILURE
, "couldn't open `%s' for writing: %s",
566 argv
[1], strerror(errno
));
569 doopen(&f
, KOPEN_WRITE
);
570 key_merge(&f
, argv
[1], fp
);
575 /*----- Main command table ------------------------------------------------*/
579 int (*cmd
)(int /*argc*/, char */
*argv*/
[]);
583 "add [-b BITS] [-e EXPIRE] [-c COMMENT] TYPE [ATTR...]" },
584 { "expire", cmd_expire
, "expire KEYID..." },
585 { "delete", cmd_delete
, "delete KEYID..." },
586 { "setattr", cmd_setattr
, "setattr KEYID ATTR..." },
587 { "comment", cmd_comment
, "comment KEYID [COMMENT]" },
588 { "list", cmd_list
, "list [-uqv]" },
589 { "tidy", cmd_tidy
, "tidy" },
590 { "extract", cmd_extract
, "extract FILE KEYID..." },
591 { "merge", cmd_merge
, "merge FILE" },
595 typedef struct cmd cmd
;
597 /*----- Main code ---------------------------------------------------------*/
599 /* --- Helpful GNUy functions --- */
603 fprintf(fp
, "Usage: %s [-k file] command [args]\n", QUIS
);
606 void version(FILE *fp
)
608 fprintf(fp
, "%s, Catacomb version " VERSION
"\n", QUIS
);
618 Performs various simple key management operations. Command line options\n\
621 -h, --help Display this help text.\n\
622 -v, --version Display version number.\n\
623 -u, --usage Display short usage summary.\n\
625 -k, --keyring=FILE Read and write keys in FILE.\n\
627 The following commands are understood:\n\n",
629 for (c
= cmds
; c
->name
; c
++)
630 fprintf(fp
, "%s\n", c
->help
);
635 * Arguments: @int argc@ = number of command line arguments
636 * @char *argv[]@ = array of command line arguments
638 * Returns: Nonzero on failure.
640 * Use: Main program. Performs simple key management functions.
643 int main(int argc
, char *argv
[])
651 /* --- Initialization --- */
656 /* --- Parse command line options --- */
659 static struct option opt
[] = {
661 /* --- Standard GNUy help options --- */
663 { "help", 0, 0, 'h' },
664 { "version", 0, 0, 'v' },
665 { "usage", 0, 0, 'u' },
667 /* --- Real live useful options --- */
669 { "keyring", OPTF_ARGREQ
, 0, 'k' },
671 /* --- Magic terminator --- */
675 int i
= mdwopt(argc
, argv
, "+hvu k:", opt
, 0, 0, 0);
681 /* --- GNU help options --- */
692 /* --- Real useful options --- */
698 /* --- Bogosity --- */
706 /* --- Complain about excessive bogons --- */
708 if (f
& f_bogus
|| optind
== argc
) {
713 /* --- Dispatch to appropriate command handler --- */
721 size_t sz
= strlen(argv
[0]);
723 for (c
= cmds
; c
->name
; c
++) {
724 if (strncmp(argv
[0], c
->name
, sz
) == 0) {
725 if (c
->name
[sz
] == 0) {
729 die(EXIT_FAILURE
, "ambiguous command name `%s'", argv
[0]);
735 die(EXIT_FAILURE
, "unknown command name `%s'", argv
[0]);
736 return (chosen
->cmd(argc
, argv
));
740 /*----- That's all, folks -------------------------------------------------*/