From 1cffa76b4fbea8014acd5f972fdbff775183b369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Mon, 15 Dec 2014 17:00:59 +0000 Subject: [PATCH] Track liboath: - Use UINT_MAX to indicate an invalid response. - The meaning of the window parameter has changed slightly. The calc command now accepts a count of codes to generate. The resync command now fails if the key is not resynchronizable. Clean up the usage message. Document exit codes. git-svn-id: svn+ssh://svn.openpam.org/svn/openpam/trunk@850 185d5e19-27fe-0310-9dcf-9bff6b9f3609 --- bin/oathkey/oathkey.1 | 20 ++++++++- bin/oathkey/oathkey.c | 95 +++++++++++++++++++++++++++---------------- 2 files changed, 79 insertions(+), 36 deletions(-) diff --git a/bin/oathkey/oathkey.1 b/bin/oathkey/oathkey.1 index 173dcda..25c05d3 100644 --- a/bin/oathkey/oathkey.1 +++ b/bin/oathkey/oathkey.1 @@ -28,7 +28,7 @@ .\" .\" $Id$ .\" -.Dd December 11, 2014 +.Dd December 15, 2014 .Dt OATHKEY 1 .Os .Sh NAME @@ -70,8 +70,11 @@ This is the default. .Pp The commands are: .Bl -tag -width 6n -.It Cm calc +.It Cm calc Op Ar count Compute and display the current code for the given key. +If a count is specified, compute and display +.Ar count +additional codes. If writeback mode is enabled, the user's keyfile is updated to prevent reuse. .It Cm genkey Ar hotp | totp @@ -100,6 +103,19 @@ user's key. If writeback mode is enabled and the response matched, the user's keyfile is updated to prevent reuse. .El +.Sh EXIT STATUS +The +.Cm verify +command exits 0 if the code is valid, 1 if it is invalid and >1 if an +error occurred. +.Pp +The +.Cm resync +command exits 0 if resynchronization was successful, 1 if it failed or +the specified key does not support resynchronization, and >1 if an +error occurred. +.Pp +All other commands exit 0 if successful and >1 if an error occurred. .Sh SEE ALSO .Xr oath_hotp 3 , .Xr oath_key 3 , diff --git a/bin/oathkey/oathkey.c b/bin/oathkey/oathkey.c index 9f6a117..34948a6 100644 --- a/bin/oathkey/oathkey.c +++ b/bin/oathkey/oathkey.c @@ -50,6 +50,10 @@ #include +/* XXX hardcoded windows */ +#define HOTP_WINDOW 9 +#define TOTP_WINDOW 1 + enum { RET_SUCCESS, RET_FAILURE, RET_ERROR, RET_USAGE, RET_UNAUTH }; static char *user; @@ -237,7 +241,8 @@ static int oathkey_verify(int argc, char *argv[]) { struct oath_key *key; - unsigned long counter, response; + unsigned long counter; + unsigned int response; char *end; int match, ret; @@ -247,17 +252,17 @@ oathkey_verify(int argc, char *argv[]) return (ret); response = strtoul(*argv, &end, 10); if (end == *argv || *end != '\0') - response = ULONG_MAX; /* never valid */ + response = UINT_MAX; /* never valid */ switch (key->mode) { - case om_totp: - match = oath_totp_match(key, response, 3 /* XXX window */); - break; case om_hotp: counter = key->counter; - match = oath_hotp_match(key, response, 17 /* XXX window */); + match = oath_hotp_match(key, response, HOTP_WINDOW); if (verbose && match > 0 && key->counter > counter + 1) warnx("skipped %lu codes", key->counter - counter - 1); break; + case om_totp: + match = oath_totp_match(key, response, TOTP_WINDOW); + break; default: match = -1; } @@ -267,7 +272,7 @@ oathkey_verify(int argc, char *argv[]) match = 0; } if (verbose) - warnx("response: %lu %s", response, + warnx("response: %u %s", response, match ? "matched" : "did not match"); ret = match ? readonly ? RET_SUCCESS : oathkey_save(key) : RET_FAILURE; oath_key_free(key); @@ -282,26 +287,41 @@ oathkey_calc(int argc, char *argv[]) { struct oath_key *key; unsigned int current; + unsigned long i, n; + char *end; int ret; - if (argc != 0) + if (argc > 1) return (RET_USAGE); - (void)argv; + if (argc > 0) { + n = strtoul(argv[0], &end, 10); + if (end == argv[0] || *end != '\0') + return (RET_USAGE); + } else { + n = 0; + } if ((ret = oathkey_load(&key)) != RET_SUCCESS) return (ret); - if (key->mode == om_totp) - current = oath_totp_current(key); - else if (key->mode == om_hotp) - current = oath_hotp_current(key); - else - current = -1; - if (current == (unsigned int)-1) { - warnx("OATH error"); - ret = RET_ERROR; - } else { + for (i = 0; i <= n; ++i) { + switch (key->mode) { + case om_hotp: + current = oath_hotp_current(key); + break; + case om_totp: + current = oath_totp_current(key); + break; + default: + current = UINT_MAX; + } + if (current == UINT_MAX) { + warnx("OATH error"); + ret = RET_ERROR; + break; + } printf("%.*d\n", (int)key->digits, current); - ret = readonly ? RET_SUCCESS : oathkey_save(key); } + if (ret == RET_SUCCESS && !readonly) + ret = oathkey_save(key); oath_key_free(key); return (ret); } @@ -313,7 +333,8 @@ static int oathkey_resync(int argc, char *argv[]) { struct oath_key *key; - unsigned long counter, response[3]; + unsigned long counter; + unsigned int response[3]; char *end; int i, match, n, ret, w; @@ -323,23 +344,28 @@ oathkey_resync(int argc, char *argv[]) for (i = 0, w = 1; i < n; ++i) { response[i] = strtoul(argv[i], &end, 10); if (end == argv[i] || *end != '\0') - response[i] = ULONG_MAX; /* never valid */ - w = w * 10; + response[i] = UINT_MAX; /* never valid */ + w = w * (HOTP_WINDOW + 1); } + w -= n; if ((ret = oathkey_load(&key)) != RET_SUCCESS) return (ret); switch (key->mode) { case om_hotp: + /* this should be a library function */ counter = key->counter; - match = oath_hotp_match(key, response[0], w); - for (i = 1; i < n && match > 0; ++i) - match = oath_hotp_match(key, response[i], 1); + while (key->counter < counter + w) { + match = oath_hotp_match(key, response[0], + counter + w - key->counter - 1); + warnx("%d", match); + if (match <= 0) + break; + for (i = 1; i < n && match > 0; ++i) + match = oath_hotp_match(key, response[i], 0); + } if (verbose && match > 0) warnx("skipped %lu codes", key->counter - counter - 1); break; - case om_totp: - match = 1; - break; default: match = -1; } @@ -361,18 +387,19 @@ static void usage(void) { fprintf(stderr, - "usage: oathkey [-hrvw] [-u user] [-k keyfile] \n" + "usage: oathkey [-hrvw] [-u user] [-k keyfile] command\n" "\n" "Commands:\n" - " calc Print the current code\n" - " genkey \n" + " calc [count]\n" + " Print the next code(s)\n" + " genkey hotp | totp\n" " Generate a new key\n" " getkey Print the key in hexadecimal form\n" " geturi Print the key in otpauth URI form\n" - " resync []\n" + " resync code1 code2 [code3]\n" " Resynchronize an HOTP token\n" " setkey Generate a new key\n" - " verify \n" + " verify code\n" " Verify an HOTP or TOTP code\n"); exit(1); }