diff -Naur totp.orig/slapd-totp.c totp/slapd-totp.c --- totp.orig/slapd-totp.c 2019-09-06 13:49:37.823864736 -0400 +++ totp/slapd-totp.c 2019-09-06 13:50:39.481021986 -0400 @@ -479,7 +479,6 @@ out.mv_val = outbuf; out.mv_len = sizeof(outbuf); generate(&key, t, DIGITS, &out, mech); - memset(key.mv_val, 0, key.mv_len); /* compare */ if (out.mv_len != cred->bv_len) { @@ -489,7 +489,21 @@ rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; + /* If current value doesn't match, try again with previous value + * but only if the most recent login is older than the previous + * time step but still set */ + if (rc == LUTIL_PASSWD_ERR && told < t - 1 && told > 0) { + out.mv_val = outbuf; + out.mv_len = sizeof(outbuf); + generate(&key, t - 1, DIGITS, &out, mech); + /* compare */ + if (out.mv_len != cred->bv_len) + goto out; + rc = memcmp(out.mv_val, cred->bv_val, out.mv_len) ? LUTIL_PASSWD_ERR : LUTIL_PASSWD_OK; + } + out: + memset(key.mv_val, 0, key.mv_len); ber_memfree(key.mv_val); return rc; } diff -Naur totp.orig/slapo-totp.5 totp/slapo-totp.5 --- totp.orig/slapo-totp.5 2019-09-06 13:50:20.160659443 -0400 +++ totp/slapo-totp.5 2019-09-06 13:47:00.204902783 -0400 @@ -72,6 +72,13 @@ The time step is hard-coded to thirty seconds. This should be OK for many use cases, but it would be nice if the value could be changed with a configuration keyword or in an attribute value. +However, after one successful initial authentication (to verify +the clocks on the server and the user's prover are in sync) the TOTP +value of the previous time window may also be used to successfully +authenticate, provided no successful bind has been performed already +in the current or previous time window. This eliminates false +negatives caused by user or network delays +entering or transmitting the TOTP value. The authenticator code that is generated is hard-coded to a length of six digits. While in most cases