/* S/KEY v1.1b (skeyinit.c)
 *
 * Authors:
 *          Neil M. Haller <nmh@thumper.bellcore.com>
 *          Philip R. Karn <karn@chicago.qualcomm.com>
 *          John S. Walden <jsw@thumper.bellcore.com>
 *          Scott Chasin <chasin@crimelab.com>
 *
 * S/KEY initialization and seed update
 */

#include <stdio.h>
#include <string.h>
#include <pwd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <time.h>

#ifdef __svr4__
#include <sys/systeminfo.h>
#include <unistd.h>
#include <shadow.h>
#include "sysv_shadow.h"
#endif /* __svr4__ */

#include "skey.h"

extern int optind;
extern char *optarg;

char *skey_readpass (), *malloc (), *getpass (), *crypt ();

int skeylookup __ARGS ((struct skey * mp, char *name));

#define NAMELEN 2

int enternumber=0;
int entersecret=1;
int enteruname=0;
int overridelocal=0;

char *Usage = "%s [-run] [-f skeyfile] [<username>]\n-r	Enter result of key instead of secret key\n-u	Enter the S/Key userid\n-n	Enter the total number of allowed logins for this userid (1-999)\n-f	Use the supplied skey file instead of /etc/skeykeys (disables suid)\n\n";


main (argc, argv)
  int argc;
  char *argv[];
{
  int c, iserror = 0;
  extern char *optarg;
  extern int optind;
  int rval, n, nn, i, l;
  time_t now;
  char seed[18], tmp[80], key[8], defaultseed[17], passwd[256], passwd2[256],
       tbuf[27], buf[60], lastc, me[80], user [8], *salt, *p, *pw; 
  struct skey skey;
  struct passwd *pp;
  struct tm *tm;

  while ((c = getopt(argc, argv, "runf:")) != -1)
    switch (c)
      {
      case 'r':
	entersecret = 0;
	break;
      case 'u':
	enteruname = 1;
	break;
      case 'n':
	enternumber=1;
	break;
      case 'f':
	overridelocal = 1;
	skey_keyfile = optarg;
	setgid(getgid());	/* Give up privs */
	setuid(getuid());	/* Give up privs */
	break;
      case '?':
	iserror++;
      }

  if (iserror || ((argc-optind) > 1) || (overridelocal && (argc-optind) != 1))
    {
      fprintf(stderr,Usage,argv[0]);
      exit(1);
    }

  time (&now);
  tm = localtime (&now);
  strftime (tbuf, sizeof (tbuf), "%M%j", tm);

  if ((gethostname (defaultseed, sizeof (defaultseed))) < 0)
      exit (-1);

  strcpy (&defaultseed[NAMELEN], tbuf);

  if (argc-optind == 1)
    {
      pp = getpwnam (argv[optind]);
      strcpy (me,argv[optind]);
    }
  else
    {
      pp = getpwuid (getuid ());
      if (pp)
	strcpy (me, pp->pw_name);
    }


  if (!overridelocal && pp == NULL)
    {
      fprintf (stderr,"User %s unknown\n",me);
      exit (1);
    }

  if (!overridelocal && strcmp (pp->pw_name, me) != 0)
    if (getuid () != 0)
      {
	/* Only root can change other's passwds */
	fprintf (stderr,"Permission denied.\n");
	exit (1);
      }


  setpriority (PRIO_PROCESS, 0, -4);

  if (!overridelocal && getuid () != 0)
    {
      setpriority (PRIO_PROCESS, 0, -4);

      pw = getpass ("Unix Password:");

      salt = pp->pw_passwd;
      p = crypt (pw, salt);

      setpriority(PRIO_PROCESS, 0, 0);

      if (pp && strcmp(p, pp->pw_passwd))
	{
	  fprintf (stderr,"Password incorrect.\n");
	  exit (-1);
	}
    }

  rval = skeylookup (&skey, me);
  switch (rval)
    {
    case -1:
      perror ("Error opening database: ");
      exit (1);
    case 0:
      printf ("[Updating %s]\n", me);
      printf ("Old key: %s\n", skey.seed);

      /* lets be nice if they have a skey.seed that ends in 0-8 just add one */
      l = strlen (skey.seed);
      if (l > 0)
	{
	  lastc = skey.seed[l - 1];
	  if (isdigit (lastc) && lastc != '9')
	    {
	      strcpy (defaultseed, skey.seed);
	    defaultseed[l - 1] = lastc + 1;
	    }
	  if (isdigit (lastc) && lastc == '9' && l < 16)
	    {
	      strcpy (defaultseed, skey.seed);
	      defaultseed[l - 1] = '0';
	      defaultseed[l] = '0';
	      defaultseed[l + 1] = '\0';
	    }
	}
      break;
    case 1:
      printf ("[Adding %s]\n", me);
      break;
    }
  n = 99;

  if (enternumber)
    for (i = 0 ;; i++)
      {
	if (i >= 2)
	  exit (1);
	printf ("Enter sequence count from 1 to 10000: ");
	fgets (tmp, sizeof (tmp), stdin);
	n = atoi (tmp);
	if (n > 0 && n < 10000)
	  break;		/* Valid range */
	fprintf (stderr,"\n Error: Count must be > 0 and < 10000\n");
      }

  if (enteruname)
    {
      printf ("Enter new key [default %s]: ", defaultseed);
      fflush (stdout);
      fgets (seed, sizeof (seed), stdin);
      skey_rip (seed);
      if (strlen (seed) > 16)
	{
	  printf ("Notice: Seed truncated to 16 characters.\n");
	  seed[16] = '\0';
	}

      if (seed[0] == '\0')
	strcpy (seed, defaultseed);
      else
	strcpy (defaultseed, seed);
    }

  if (!entersecret)
    {
      printf ("You need the 6 english words generated from the \"key\" command.\n");
      for (i = 0 ;; i++)
	{
	  if (i >= 2)
	    exit (1);

	  printf ("s/key %d %s\ns/key access password: ", n, seed);
	  fgets (tmp, sizeof (tmp), stdin);
	  skey_rip (tmp);
	  skey_backspace (tmp);

	  if (tmp[0] == '?')
	    {
	      printf ("Enter 6 English words from secure S/Key calculation.\n");
	      continue;
	    }

	  if (tmp[0] == '\0')
	    {
	      exit (1);
	    }
	  if (skey_etob (key, tmp) == 1 || skey_atob8 (key, tmp) == 0)
	    break;		/* Valid format */
	  fprintf (stderr,"Invalid format - try again with 6 English words from secure S/Key calculation.\n");
	}
    }
  else
    {
      /* Get user's secret password */
      for (i = 0 ;; i++)
	{

	  if (i >= 2)
	    exit (1);

	  printf ("Enter secret password: ");
	  skey_readpass (passwd, sizeof (passwd));

	  if (passwd[0] == '\0')
	    exit (1);

	  printf ("Again secret password: ");
	  skey_readpass (passwd2, sizeof (passwd));

	  if (passwd2[0] == '\0')
	    exit (1);

	  if (strlen (passwd) < 4 && strlen (passwd2) < 4)
	    {
	      fprintf (stderr, "Error: Your password must be longer.\n\r");
	      exit (1);
	    }

	  if (strcmp (passwd, passwd2) == 0)
	    break;

	  printf ("Error: Passwords dont match.\n");
	}
      strcpy (seed, defaultseed);

      /* Crunch seed and password into starting key */
      if (skey_keycrunch (key, seed, passwd) != 0)
	{
	  fprintf (stderr, "%s: key crunch failed.\n", argv[0]);
	  exit (2);
	}
      nn = n;
      while (nn-- != 0)
	skey_f (key);
    }
  time (&now);
  tm = localtime (&now);
  strftime (tbuf, sizeof (tbuf), " %b %d,%Y %T", tm);

  skey.val = malloc (16 + 1);

  skey_btoa8 (skey.val, key);

  fprintf (skey.keyfile, "%s %04d %-16s %s %-21s\n", me, n,
	   seed, skey.val, tbuf);
  fclose (skey.keyfile);
  printf ("\nID %s s/key is %d %s\n", me, n, seed);
  printf ("Next login password: %s\n", skey_btoe (buf, key));
#ifdef HEXIN
  printf ("%s\n", put8 (buf, key));
#endif

  exit (1);
}

#ifdef __svr4__
int gethostname (name, len)
char *name;
int len;
{ 
   int  namelen = 128;
 
   if (sysinfo (SI_HOSTNAME, name, len) <0)  {
        perror("hostname");
        return -1;
   }
   return 0;
}
#endif
