Example #1
0
int
main (int argc, char *argv[])
{
  struct gengetopt_args_info args_info;
  char *secret;
  size_t secretlen = 0;
  int rc;
  size_t window;
  uint64_t moving_factor;
  unsigned digits;
  char otp[10];
  time_t now, when, t0, time_step_size;
  int totpflags = 0;

  set_program_name (argv[0]);

  if (cmdline_parser (argc, argv, &args_info) != 0)
    return EXIT_FAILURE;

  if (args_info.version_given)
    {
      char *p;
      int l = -1;

      if (strcmp (oath_check_version (NULL), OATH_VERSION) != 0)
	l = asprintf (&p, "OATH Toolkit liboath.so %s oath.h %s",
		      oath_check_version (NULL), OATH_VERSION);
      else if (strcmp (OATH_VERSION, PACKAGE_VERSION) != 0)
	l = asprintf (&p, "OATH Toolkit %s",
		      oath_check_version (NULL), OATH_VERSION);
      version_etc (stdout, "oathtool", l == -1 ? "OATH Toolkit" : p,
		   PACKAGE_VERSION, "Simon Josefsson", (char *) NULL);
      if (l != -1)
	free (p);
      return EXIT_SUCCESS;
    }

  if (args_info.help_given)
    usage (EXIT_SUCCESS);

  if (args_info.inputs_num == 0)
    {
      cmdline_parser_print_help ();
      emit_bug_reporting_address ();
      return EXIT_SUCCESS;
    }

  rc = oath_init ();
  if (rc != OATH_OK)
    error (EXIT_FAILURE, 0, "liboath initialization failed: %s",
	   oath_strerror (rc));

  if (args_info.base32_flag)
    {
      rc = oath_base32_decode (args_info.inputs[0],
			       strlen (args_info.inputs[0]),
			       &secret, &secretlen);
      if (rc != OATH_OK)
	error (EXIT_FAILURE, 0, "base32 decoding failed: %s",
	       oath_strerror (rc));
    }
  else
    {
      secretlen = 1 + strlen (args_info.inputs[0]) / 2;
      secret = malloc (secretlen);
      if (!secret)
	error (EXIT_FAILURE, errno, "malloc");

      rc = oath_hex2bin (args_info.inputs[0], secret, &secretlen);
      if (rc != OATH_OK)
	error (EXIT_FAILURE, 0, "hex decoding of secret key failed");
    }

  if (args_info.counter_orig)
    moving_factor = args_info.counter_arg;
  else
    moving_factor = 0;

  if (args_info.digits_orig)
    digits = args_info.digits_arg;
  else
    digits = 6;

  if (args_info.window_orig)
    window = args_info.window_arg;
  else
    window = 0;

  if (digits != 6 && digits != 7 && digits != 8)
    error (EXIT_FAILURE, 0, "only digits 6, 7 and 8 are supported");

  if (validate_otp_p (args_info.inputs_num) && !args_info.digits_orig)
    digits = strlen (args_info.inputs[1]);
  else if (validate_otp_p (args_info.inputs_num) && args_info.digits_orig &&
	   args_info.digits_arg != strlen (args_info.inputs[1]))
    error (EXIT_FAILURE, 0,
	   "given one-time password has bad length %d != %ld",
	   args_info.digits_arg, strlen (args_info.inputs[1]));

  if (args_info.inputs_num > 2)
    error (EXIT_FAILURE, 0, "too many parameters");

  if (args_info.verbose_flag)
    {
      char *tmp;

      tmp = malloc (2 * secretlen + 1);
      if (!tmp)
	error (EXIT_FAILURE, errno, "malloc");

      oath_bin2hex (secret, secretlen, tmp);

      printf ("Hex secret: %s\n", tmp);
      free (tmp);

      rc = oath_base32_encode (secret, secretlen, &tmp, NULL);
      if (rc != OATH_OK)
	error (EXIT_FAILURE, 0, "base32 encoding failed: %s",
	       oath_strerror (rc));

      printf ("Base32 secret: %s\n", tmp);
      free (tmp);

      if (args_info.inputs_num == 2)
	printf ("OTP: %s\n", args_info.inputs[1]);
      printf ("Digits: %d\n", digits);
      printf ("Window size: %ld\n", window);
    }

  if (args_info.totp_given)
    {
      now = time (NULL);
      when = parse_time (args_info.now_arg, now);
      t0 = parse_time (args_info.start_time_arg, now);
      time_step_size = parse_duration (args_info.time_step_size_arg);

      if (when == BAD_TIME)
	error (EXIT_FAILURE, 0, "cannot parse time `%s'", args_info.now_arg);

      if (t0 == BAD_TIME)
	error (EXIT_FAILURE, 0, "cannot parse time `%s'",
	       args_info.start_time_arg);

      if (time_step_size == BAD_TIME)
	error (EXIT_FAILURE, 0, "cannot parse time `%s'",
	       args_info.time_step_size_arg);

      if (strcmp (args_info.totp_arg, "sha256") == 0)
	totpflags = OATH_TOTP_HMAC_SHA256;
      else if (strcmp (args_info.totp_arg, "sha512") == 0)
	totpflags = OATH_TOTP_HMAC_SHA512;

      if (args_info.verbose_flag)
	verbose_totp (t0, time_step_size, when);
    }
  else
    {
      if (args_info.verbose_flag)
	verbose_hotp (moving_factor);
    }

  if (generate_otp_p (args_info.inputs_num) && !args_info.totp_given)
    {
      size_t iter = 0;

      do
	{
	  rc = oath_hotp_generate (secret,
				   secretlen,
				   moving_factor + iter,
				   digits,
				   false, OATH_HOTP_DYNAMIC_TRUNCATION, otp);
	  if (rc != OATH_OK)
	    error (EXIT_FAILURE, 0,
		   "generating one-time password failed (%d)", rc);

	  printf ("%s\n", otp);
	}
      while (window - iter++ > 0);
    }
  else if (generate_otp_p (args_info.inputs_num) && args_info.totp_given)
    {
      size_t iter = 0;

      do
	{
	  rc = oath_totp_generate2 (secret,
				    secretlen,
				    when + iter * time_step_size,
				    time_step_size, t0, digits, totpflags,
				    otp);
	  if (rc != OATH_OK)
	    error (EXIT_FAILURE, 0,
		   "generating one-time password failed (%d)", rc);

	  printf ("%s\n", otp);
	}
      while (window - iter++ > 0);
    }
  else if (validate_otp_p (args_info.inputs_num) && !args_info.totp_given)
    {
      rc = oath_hotp_validate (secret,
			       secretlen,
			       moving_factor, window, args_info.inputs[1]);
      if (rc == OATH_INVALID_OTP)
	error (EXIT_OTP_INVALID, 0,
	       "password \"%s\" not found in range %ld .. %ld",
	       args_info.inputs[1],
	       (long) moving_factor, (long) moving_factor + window);
      else if (rc < 0)
	error (EXIT_FAILURE, 0,
	       "validating one-time password failed (%d)", rc);
      printf ("%d\n", rc);
    }
  else if (validate_otp_p (args_info.inputs_num) && args_info.totp_given)
    {
      rc = oath_totp_validate4 (secret,
				secretlen,
				when,
				time_step_size,
				t0,
				window,
				NULL, NULL, totpflags, args_info.inputs[1]);
      if (rc == OATH_INVALID_OTP)
	error (EXIT_OTP_INVALID, 0,
	       "password \"%s\" not found in range %ld .. %ld",
	       args_info.inputs[1],
	       (long) ((when - t0) / time_step_size - window / 2),
	       (long) ((when - t0) / time_step_size + window / 2));
      else if (rc < 0)
	error (EXIT_FAILURE, 0,
	       "validating one-time password failed (%d)", rc);
      printf ("%d\n", rc);
    }

  free (secret);
  oath_done ();

  return EXIT_SUCCESS;
}
Example #2
0
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;
}