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 -------------------------------------------------*/