/* opiekey.c: Stand-alone program for computing responses to OTP challenges.

 Takes a sequence number and seed (presumably from an OPIE challenge)
 as command line arguments, prompts for the user's secret password,
 and outputs a response.

Portions of this software are Copyright 1995 by Randall Atkinson and Dan
McDonald, All Rights Reserved. All Rights under this copyright are assigned
to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
License Agreement applies to this software.

	History:

	Modified at NRL for OPIE 2.0.
	Written at Bellcore for the S/Key Version 1 software distribution
		(skey.c).
*/
#include "opie_cfg.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "opie.h"

#ifdef	__MSDOS__
#include <dos.h>
#endif

#if HAVE_FCNTL_H
#include <fcntl.h>
#endif /* HAVE_FCNTL_H */

extern char *optarg;
extern int optind, opterr;



/******** Begin real source code ***************/

void usage(s)
char *s;
{
  fprintf(stderr, "usage: %s [-v] [-h] [-4 | -5] [-d] [-a] [-n count] sequence_number seed\n", s);
  exit(1);
}

int main(argc, argv)
int argc;
char *argv[];
{
  /* variable declarations */
  unsigned algorithm = MDX;	/* default algorithm per Makefile's MDX
				   symbol */
  int keynum = 0;
  int i = 0;
  int count = 1;
  char passwd[OPIE_PASS_MAX + 1];
  char key[8];
  char *seed;
  char buf[33];
  char *slash;
  int aflag = 0;

#ifdef MJR
  int desmode = 0;

#define MJROPT "d"
#else	/* MJR */
#define MJROPT
#endif	/* MJR */

  if (slash = strchr(argv[0], '/'))
    slash++;
  else
    slash = argv[0];

#ifdef MJR
  if (strstr(slash, "des"))
    desmode = 1;
#endif	/* MJR */

  if (!strcmp(slash, "key") || strstr(slash, "md4"))
    algorithm = 4;

  if (strstr(slash, "md5"))
    algorithm = 5;

  while ((i = getopt(argc, argv, MJROPT "hvn:45a")) != EOF) {
    switch (i) {
    case 'v':
      opieversion();

#ifdef MJR
    case 'd':
      desmode = 1;
      break;
#endif

    case 'n':
      count = atoi(optarg);
      break;

    case '4':
      /* use MD4 algorithm */
      algorithm = 4;
      break;

    case '5':
      /* use MD5 algorithm */
      algorithm = 5;
      break;

    case 'a':
      aflag = 1;
      break;

    default:
      usage(argv[0]);
    }
  }

  if ((argc - optind) < 2)
    usage(argv[0]);

  fprintf(stderr, "Using MD%d algorithm to compute response.\n", algorithm);

  /* get sequence number, which is next-to-last parameter */
  keynum = atoi(argv[optind]);
  if (keynum < 1) {
    fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]);
    exit(1);
  }
  /* get seed string, which is last parameter */
  seed = argv[optind + 1];

  fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n");

  if (opieinsecure()) {
    fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
    exit(1);
  }
  /* Get user's secret password */
  fprintf(stderr, "Enter secret pass phrase: ");
  opiereadpass(passwd, sizeof(passwd));
#if RETYPE
  {
    char verify[OPIE_PASS_MAX + 1];

    fprintf(stderr, "Again secret pass phrase: ");
    opiereadpass(verify, sizeof(verify));
    if (verify[0] && strncmp(verify, passwd, sizeof(passwd))) {
      fprintf(stderr, "They don't match. Try again.\n");
      exit(1);
    }
  }
#endif	/* RETYPE */
  if ((!aflag) && opiepasscheck(passwd)) {
    fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_PASS_MIN, OPIE_PASS_MAX);
    exit(1);
  };

#ifdef MJR
  /* Crunch seed and secret password into starting key using DES */
  if (desmode ? deskeycrunch(key, seed, passwd) :
      opiekeycrunch(algorithm, key, seed, passwd) != 0) {
    fprintf(stderr, "%s: DES key crunch failed\n", argv[0]);
    return 1;
  }
#else
  /* Crunch seed and secret password into starting key normally */
  if (opiekeycrunch(algorithm, key, seed, passwd) != 0) {
    fprintf(stderr, "%s: key crunch failed\n", argv[0]);
    return 1;
  }
#endif

  if (count == 1) {
    while (keynum-- != 0)
      opiehash(key, algorithm);
    printf("%s\n", opiebtoe(buf, key));
  } else {
    for (i = 0; i <= (keynum - count); i++)
      opiehash(key, algorithm);

    for (; i <= keynum; i++) {
      printf("%d: %-29s\n", i, opiebtoe(buf, key));
      opiehash(key, algorithm);
    }
  }
  return 0;
}
