/** * oath_totp_validate: * @secret: the shared secret string * @secret_length: length of @secret * @now: Unix time value to validate TOTP for * @time_step_size: time step system parameter (typically 30) * @start_offset: Unix time of when to start counting time steps (typically 0) * @window: how many OTPs after/before start OTP to test * @otp: the OTP to validate. * * Validate an OTP according to OATH TOTP algorithm per RFC 6238. * * Currently only OTP lengths of 6, 7 or 8 digits are supported. This * restrictions may be lifted in future versions, although some * limitations are inherent in the protocol. * * Returns: Returns absolute value of position in OTP window (zero is * first position), or %OATH_INVALID_OTP if no OTP was found in OTP * window, or an error code. * * Since: 1.6.0 **/ int oath_totp_validate (const char *secret, size_t secret_length, time_t now, unsigned time_step_size, time_t start_offset, size_t window, const char *otp) { return oath_totp_validate2 (secret, secret_length, now, time_step_size, start_offset, window, NULL, otp); }
static int parse_usersfile (const char *username, const char *otp, size_t window, const char *passwd, time_t * last_otp, FILE * infh, char **lineptr, size_t * n, uint64_t * new_moving_factor) { while (getline (lineptr, n, infh) != -1) { char *saveptr; char *p = strtok_r (*lineptr, whitespace, &saveptr); unsigned digits, totpstepsize; char secret[32]; size_t secret_length = sizeof (secret); uint64_t start_moving_factor = 0; int rc; char *prev_otp = NULL; if (p == NULL) continue; /* Read token type */ if (parse_type (p, &digits, &totpstepsize) != 0) continue; /* Read username */ p = strtok_r (NULL, whitespace, &saveptr); if (p == NULL || strcmp (p, username) != 0) continue; /* Read password. */ p = strtok_r (NULL, whitespace, &saveptr); if (passwd) { if (p == NULL) continue; if (strcmp (p, "-") == 0) { if (*passwd != '\0') return OATH_BAD_PASSWORD; } else if (strcmp (p, passwd) != 0) return OATH_BAD_PASSWORD; } /* Read key. */ p = strtok_r (NULL, whitespace, &saveptr); if (p == NULL) continue; rc = oath_hex2bin (p, secret, &secret_length); if (rc != OATH_OK) return rc; /* Read (optional) moving factor. */ p = strtok_r (NULL, whitespace, &saveptr); if (p && *p) { char *endptr; unsigned long long int ull = strtoull (p, &endptr, 10); if (endptr && *endptr != '\0') return OATH_INVALID_COUNTER; start_moving_factor = ull; } /* Read (optional) last OTP */ prev_otp = strtok_r (NULL, whitespace, &saveptr); /* Read (optional) last_otp */ p = strtok_r (NULL, whitespace, &saveptr); if (p) { struct tm tm; char *ts; ts = strptime (p, TIME_FORMAT_STRING, &tm); if (ts == NULL || *ts != '\0') return OATH_INVALID_TIMESTAMP; tm.tm_isdst = -1; if (last_otp) { *last_otp = mktime (&tm); if (*last_otp == (time_t) - 1) return OATH_INVALID_TIMESTAMP; } } if (prev_otp && strcmp (prev_otp, otp) == 0) return OATH_REPLAYED_OTP; if (totpstepsize == 0) rc = oath_hotp_validate (secret, secret_length, start_moving_factor, window, otp); else if (prev_otp) { int prev_otp_pos, this_otp_pos, tmprc; rc = oath_totp_validate2 (secret, secret_length, time (NULL), totpstepsize, 0, window, &this_otp_pos, otp); if (rc < 0) return rc; tmprc = oath_totp_validate2 (secret, secret_length, time (NULL), totpstepsize, 0, window, &prev_otp_pos, prev_otp); if (tmprc >= 0 && prev_otp_pos >= this_otp_pos) return OATH_REPLAYED_OTP; } else rc = oath_totp_validate (secret, secret_length, time (NULL), totpstepsize, 0, window, otp); if (rc < 0) return rc; *new_moving_factor = start_moving_factor + rc; return OATH_OK; } return OATH_UNKNOWN_USER; }