From 38622bad18f67c237ab20fc34cdbfd057d5e438b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Mon, 10 Mar 2014 15:31:30 +0000 Subject: [PATCH] Implement keyfile writeback. git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@784 185d5e19-27fe-0310-9dcf-9bff6b9f3609 --- bin/oathkey/oathkey.1 | 8 +++- bin/oathkey/oathkey.c | 85 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 77 insertions(+), 16 deletions(-) diff --git a/bin/oathkey/oathkey.1 b/bin/oathkey/oathkey.1 index 8c21c75..d9c023c 100644 --- a/bin/oathkey/oathkey.1 +++ b/bin/oathkey/oathkey.1 @@ -36,7 +36,7 @@ .Nd OATH key management tool .Sh SYNOPSIS .Nm -.Op Fl hv +.Op Fl hvw .Op Fl u Ar user .Op Fl k Ar keyfile .Ar command @@ -61,12 +61,16 @@ The default is the current user. Only root may operate on other users. .It Fl v Enable verbose mode. +.It Fl w +Enable writeback mode (see below). .El .Pp The commands are: .Bl -tag -width 6n .It Cm genkey Generate a new key. +If writeback mode is enabled, the user's key is set; otherwise, it is +printed to standard output. .It Cm setkey Ar uri Set the user's key to the given otpauth URI. .It Cm uri @@ -74,6 +78,8 @@ Print the user's key in otpauth URI form. .It Cm verify Ar code Verify that the given code is the correct current response for the user's key. +If writeback mode is enabled and the response matched, the user's +keyfile is updated to prevent reuse. .El .Sh SEE ALSO .Xr oath_hotp 3 , diff --git a/bin/oathkey/oathkey.c b/bin/oathkey/oathkey.c index 49ac3ee..f01f992 100644 --- a/bin/oathkey/oathkey.c +++ b/bin/oathkey/oathkey.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -54,10 +55,60 @@ enum { RET_SUCCESS, RET_FAILURE, RET_ERROR, RET_USAGE, RET_UNAUTH }; static char *user; static char *keyfile; static int verbose; +static int writeback; static int isroot; /* running as root */ static int issameuser; /* real user same as target user */ +/* + * Print key in otpauth URI form + */ +static int +oathkey_print(struct oath_key *key) +{ + char *keyuri; + + if ((keyuri = oath_key_to_uri(key)) == NULL) { + warnx("failed to convert key to otpauth URI"); + return (RET_ERROR); + } + printf("%s\n", keyuri); + free(keyuri); + return (RET_SUCCESS); +} + +/* + * Save key to file + * XXX liboath should take care of this for us + */ +static int +oathkey_save(struct oath_key *key) +{ + char *keyuri; + int fd, len, ret; + + keyuri = NULL; + len = 0; + fd = ret = -1; + if ((keyuri = oath_key_to_uri(key)) == NULL) { + warnx("failed to convert key to otpauth URI"); + goto done; + } + len = strlen(keyuri); + if ((fd = open(keyfile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0 || + write(fd, keyuri, len) != len || write(fd, "\n", 1) != 1) { + warn("%s", keyfile); + goto done; + } + ret = 0; +done: + if (fd >= 0) + close(fd); + if (keyuri != NULL) + free(keyuri); + return (ret); +} + /* * Generate a new key */ @@ -65,6 +116,7 @@ static int oathkey_genkey(int argc, char *argv[]) { struct oath_key *key; + int ret; /* XXX add parameters later */ if (argc != 0) @@ -77,10 +129,9 @@ oathkey_genkey(int argc, char *argv[]) if ((key = oath_key_create(user, om_totp, oh_undef, NULL, 0)) == NULL) return (RET_ERROR); - /* XXX should save to file, not print */ - printf("%s\n", oath_key_to_uri(key)); + ret = writeback ? oathkey_save(key) : oathkey_print(key); oath_key_free(key); - return (RET_SUCCESS); + return (ret); } /* @@ -90,6 +141,7 @@ static int oathkey_setkey(int argc, char *argv[]) { struct oath_key *key; + int ret; /* XXX add parameters later */ if (argc != 1) @@ -102,10 +154,9 @@ oathkey_setkey(int argc, char *argv[]) if ((key = oath_key_from_uri(argv[0])) == NULL) return (RET_ERROR); - /* XXX should save to file, not print */ - printf("%s\n", oath_key_to_uri(key)); + ret = oathkey_save(key); oath_key_free(key); - return (RET_SUCCESS); + return (ret); } /* @@ -115,6 +166,7 @@ static int oathkey_uri(int argc, char *argv[]) { struct oath_key *key; + int ret; if (argc != 0) return (RET_USAGE); @@ -126,9 +178,9 @@ oathkey_uri(int argc, char *argv[]) if ((key = oath_key_from_file(keyfile)) == NULL) return (RET_ERROR); - printf("%s\n", oath_key_to_uri(key)); + ret = oathkey_print(key); oath_key_free(key); - return (RET_SUCCESS); + return (ret); } /* @@ -140,7 +192,7 @@ oathkey_verify(int argc, char *argv[]) struct oath_key *key; unsigned long response; char *end; - int match; + int match, ret; if (argc < 1) return (RET_USAGE); @@ -163,11 +215,11 @@ oathkey_verify(int argc, char *argv[]) if (verbose) warnx("response: %lu %s", response, match ? "matched" : "did not match"); - if (match) { - /* XXX write key back! */ - } + ret = match ? RET_SUCCESS : RET_FAILURE; + if (match && writeback) + ret = oathkey_save(key); oath_key_free(key); - return (match ? RET_SUCCESS : RET_FAILURE); + return (ret); } /* @@ -177,7 +229,7 @@ static void usage(void) { fprintf(stderr, - "usage: oathkey [-hv] [-u user] [-k keyfile] \n" + "usage: oathkey [-hvw] [-u user] [-k keyfile] \n" "\n" "Commands:\n" " genkey Generate a new key\n" @@ -198,7 +250,7 @@ main(int argc, char *argv[]) /* * Parse command-line options */ - while ((opt = getopt(argc, argv, "hk:u:v")) != -1) + while ((opt = getopt(argc, argv, "hk:u:vw")) != -1) switch (opt) { case 'k': keyfile = optarg; @@ -209,6 +261,9 @@ main(int argc, char *argv[]) case 'v': ++verbose; break; + case 'w': + ++writeback; + break; case 'h': default: usage();