#if !defined(lint) && !defined(__INSIGHT__)
static char sos__rcsid[] = "auth.c,v 1.1.1.1 1995/06/16 21:10:48 seth Exp";
static char sos__copyright[] = "Copyright (c) 1994, 1995 SOS Corporation";
static char sos__contact[] = "SOS Corporation <sos-info@soscorp.com> +1 800 SOS UNIX";
#endif /* not lint */

/*
 * ++Copyright Released Product++
 *
 * Copyright (c) 1994, 1995 Sources of Supply Corporation ("SOS").
 * All rights reserved.
 *
 * The SOS Released Product License Agreement specifies the terms and
 * conditions for redistribution.  You may find the License Agreement
 * in the file LICENSE.
 *
 * SOS Corporation
 * 461 5th Ave.; 16th floor
 * New York, NY 10017
 *
 * +1 800 SOS UNIX
 * <sos-info@soscorp.com>
 *
 * --Copyright Released Product--
 */

/*
 * Everything we know about authentication
 */

#include "sos.h"
#include "interface.h"
#include "readconf.h"

#ifdef SKEY_AUTH
#include "skey.h"		/* Bellcore S/Key */
#endif /*SKEY_AUTH*/

#ifdef ENIGMA_AUTH
#include "custpb.h"		/* Enigma */
#if ( ENIGMA_AUTH == 3 )
#include "custf.h"		/* Enigma */
#endif
#if ( ENIGMA_AUTH == 4 )
#include "custfail.h"		/* Enigma */
#endif

#endif /*ENIGMA_AUTH*/

#ifdef SECURID_AUTH
#include "sdi_athd.h"		/* SecurID */
#include "sdi_size.h"		/* SecurID */
#include "sdi_type.h"		/* SecurID */
#include "sdacmvls.h"		/* SecurID */
#include "sdconf.h"		/* SecurID */
#endif /*SECURID_AUTH*/


struct auth_t auths[] =
{
#ifdef NULL_AUTH
  {
    "NULL", "/dev/null authenticator", null_challenge, null_auth,
    null_passwd, null_state, null_cleanup
  },
#endif /*NULL_AUTH*/
#ifdef TEST_AUTH
  {
    "TEST", "test authenticator", test_challenge, test_auth,
    test_passwd, test_state, test_cleanup
  },
#endif /*TEST_AUTH*/
#ifdef UNIX_AUTH
  {
    "PASS", "Unix Password Encryption", unix_challenge, unix_auth,
    unix_passwd, unix_state, unix_cleanup
  },
#endif /*UNIX_AUTH*/
#ifdef SKEY_AUTH
  {
    "SKEY", "Bellcore S/Key Authenticator", skey_challenge, skey_auth,
    skey_passwd, skey_state, skey_cleanup
  },
#endif /*SKEY_AUTH*/
#ifdef ENIGMA_AUTH
  {
    "ENIG", "Enigma Safeword", enig_challenge, enig_auth,
    enig_passwd, enig_state, enig_cleanup
  },
#endif /*ENIGMA_AUTH*/
#ifdef SECURID_AUTH
  {
    "SID", "Security Dynamics SecurID", sid_challenge, sid_auth,
    sid_passwd, sid_state, sid_cleanup
  },
#endif /*SECURID_AUTH*/
#ifdef CCARD_AUTH
  {
    "CCARD", "CRYPTOCard", ccard_challenge, ccard_auth,
    ccard_passwd, ccard_state, ccard_cleanup
  },
#endif /*CCARD_AUTH*/
#ifdef HASH_STATIC_AUTH
  {
    "SHASH", "SOS's HASH Static", hash_static_challenge, hash_static_auth,
    hash_static_passwd, hash_static_state, hash_static_cleanup
  },
#endif /*HASH_STATIC_AUTH*/
#ifdef HASH_DYNAMIC_AUTH
  {
    "DHASH", "SOS's HASH Dynamic", hash_dynamic_challenge, hash_dynamic_auth,
    hash_dynamic_passwd, hash_dynamic_state, hash_dynamic_cleanup
  },
#endif /*HASH_DYNAMIC_AUTH*/
  {
    NULL, NULL, NULL, NULL, NULL, NULL, NULL
  }
};


/*
 * Find the authenticator structure for this authtype
 */
struct auth_t *findauth(char *key)
{
  struct auth_t *cur;

  for(cur=auths;cur->key;cur++)
    {
      if (!strcmp(key,cur->key))
	return(cur);
    }
  return (NULL);
}



#ifdef NULL_AUTH
/**********************************************************************/
/*                                                                    */
/*			 Null Authentication			      */
/*                                                                    */
/**********************************************************************/
int null_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  return(AUTH_SUCCEED);
}

/********************************************************************/
int null_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  return(AUTH_SUCCEED);
}

/********************************************************************/
int null_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }

  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for null authenticator, user %s (denied)",user);

  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  return(AUTH_FAIL);
}

/********************************************************************/
int null_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);

  sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);

  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  return(AUTH_ERROR);
}

/********************************************************************/
void null_cleanup(char *user, char *acode)
{
  return;
}
#endif /*NULL_AUTH*/



#ifdef TEST_AUTH
/**********************************************************************/
/*                                                                    */
/*			 Test Authentication			      */
/*                                                                    */
/**********************************************************************/
int test_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  strcpy(outbuf->str,"This is the test authenticator");
  
  *nextstate = 1;
  *req_input = BS_NO_INPUT;

  return(AUTH_SUCCEED);
}

/********************************************************************/
int test_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  
  *nextstate = 5;
  *req_input = BS_NO_INPUT;

  return(AUTH_SUCCEED);
}

/********************************************************************/
int test_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }

  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for test authenticator, user %s (denied)",user);

  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  return(AUTH_FAIL);
}

/********************************************************************/
int test_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);

  switch (*nextstate)
    {
      case 1: strcpy(outbuf->str,"This is a multi-line output"); break;
      case 2: strcpy(outbuf->str,"It can be useful for instructions"); break;
      case 3: strcpy(outbuf->str,"or other actions for new users"); break;
      case 4: strcpy(outbuf->str,"or users who need additional authentication"); break;
      case 5: sprintf(outbuf->str,"This is a multi-line auth output (you said %s)",inbuf->str); break;
      case 6: sprintf(outbuf->str,"It can be useful for auth instructions (you said %s)",inbuf->str); break;
      case 7: sprintf(outbuf->str,"or other actions for new auth users (you said %s)",inbuf->str); break;
      case 8: sprintf(outbuf->str,"or users who need additional auth (you said %s)",inbuf->str); break;
      default:
	sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);
	*req_input = BS_NO_INPUT;
	*nextstate = 0;
	return(AUTH_ERROR);
      }


#if 0
  if (*nextstate > 4 && *nextstate < 8)
    *req_input = BS_SIMPLE_INPUT;
  else
#endif
    *req_input = BS_NO_INPUT;

  ++(*nextstate);
  if (*nextstate == 5)
    {
      *req_input = BS_SIMPLE_INPUT;
      *nextstate = 0;
    }
  if (*nextstate == 9)
    *nextstate = 0;

  return(AUTH_SUCCEED);
}

/********************************************************************/
void test_cleanup(char *user, char *acode)
{
#ifdef VDEBUG
  printf("This is illegal--cleanup should not printf\r\n");
#endif /*VDEBUG*/
  return;
}
#endif /*TEST_AUTH*/



#ifdef UNIX_AUTH
/**********************************************************************/
/*                                                                    */
/*			 Unix Authentication			      */
/*                                                                    */
/**********************************************************************/
int unix_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NOECHO_INPUT;

  sprintf(outbuf->str, "Please enter password");

  return(AUTH_SUCCEED);
}

/********************************************************************/
int unix_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  char salt[2];
  char *key;

  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sos_rip(inbuf->str);

  if (strlen(acode) != 13)
    {
      sprintf(bs_auth_extended,"Invalid key length (%s)\n",acode);
      return(AUTH_ERROR);
    }
  memcpy(salt,acode,2);

  key = crypt(inbuf->str, salt);

  return(memcmp(key,acode,13)?AUTH_FAIL:AUTH_SUCCEED);
}

/********************************************************************/
int unix_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  /* XXX - Should handle this */
  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for unix authenticator, user %s (denied)", user);

  return(AUTH_FAIL);
}

/********************************************************************/
int unix_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);

  return(AUTH_ERROR);
}

/********************************************************************/
void unix_cleanup(char *user, char *acode)
{
  return;
}
#endif /*UNIX_AUTH*/



#ifdef SKEY_AUTH
/**********************************************************************/
/*                                                                    */
/*			 S/Key Authentication			      */
/*                                                                    */
/**********************************************************************/
int skey_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  struct skey mp;

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }

  if (skeylookup(&mp,user))
    {
      sprintf(bs_auth_extended,"User (%s) is unknown by S/Key",user);
      return(AUTH_ERROR);
    }

  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_SIMPLE_INPUT;

  sprintf(outbuf->str,"Challenge:  s/key %d %s",mp.n-1,mp.seed);

  return(AUTH_SUCCEED);
}

/********************************************************************/
int skey_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  struct skey mp;

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sos_rip(inbuf->str);

  if (skeylookup(&mp,user))
    {
      sprintf(bs_auth_extended,"User (%s) is unknown by S/Key",user);
      return(AUTH_ERROR);
    }

  if (skeyverify(&mp,inbuf->str) == 0)
    {
      if (mp.n < 5)
	{
	  sprintf(outbuf->str,"Warning! Key initialization needed soon. (%d logins left)\n", mp.n);
	}
      return AUTH_SUCCEED;
    }
  return AUTH_FAIL;
}

/********************************************************************/
int skey_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  /* XXX - Should keyinit */
  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for S/Key authenticator, user %s (denied)", user);

  return(AUTH_FAIL);
}

/********************************************************************/
int skey_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);

  return(AUTH_ERROR);
}

/********************************************************************/
void skey_cleanup(char *user, char *acode)
{
  return;
}
#endif /*SKEY_AUTH*/



#ifdef ENIGMA_AUTH
/**********************************************************************/
/*                                                                    */
/*			Enigma Authentication			      */
/*                                                                    */
/**********************************************************************/
static struct  pblk    pblock;
static enigma_initialized = 0;

int enig_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  if (enigma_initialized)
    enig_cleanup(user,acode);

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  *nextstate = 0;
  *req_input = BS_SIMPLE_INPUT;

  memset(&pblock, 0, sizeof(pblock));
  pblock.status = NO_STATUS;
  pblock.mode = CHALLENGE;
  /*
   * Let's see if it comes up in the logs.
   * -- it does.
   */
  strcpy(pblock.uport, "auth");
  strcpy(pblock.id, user);

  pbmain(&pblock);

#if ENIGMA_AUTH == 3
  if (pblock.dynpwdf == ENABLED && pblock.status != GOOD_NO_CHAL)
#endif
#if ENIGMA_AUTH == 4
  if (pblock.dynpwdf == ENABLED )
#endif
    {
      memset(outbuf->str, 0, outbuf->len);
      if (pblock.chal[0] != '\0')
	{
	  sprintf(outbuf->str,"Enigma Challenge: <%s>",pblock.chal);
	}
      else
	{
	  sprintf(outbuf->str,"Enter Dynamic Password");
	}
      enigma_initialized = 1;
      return (AUTH_SUCCEED);
    }

  sprintf(bs_auth_extended,"Failed %s - %s",pblock.msg1,pblock.msg2);
  return(AUTH_ERROR);
}

/********************************************************************/
int enig_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  int ret;

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sos_rip(inbuf->str);

  if (!enigma_initialized)
    {
      sprintf(bs_auth_extended, "Enigma not initialized for %s (must get challenge first)",user);
      return(AUTH_ERROR);
    }

  pblock.mode = EVALUATE_ALL;
  strcpy(pblock.dynpwd, inbuf->str);
  pbmain(&pblock);

  if (pblock.status == PASS || pblock.status == PASS_MASTER)
    {
      sprintf(outbuf->str,"Passed %s - %s",pblock.msg1,pblock.msg2);
      ret = AUTH_SUCCEED;
    }
  else
    {
      sprintf(outbuf->str,"Failed %s - %s",pblock.msg1,pblock.msg2);
      ret = AUTH_FAIL;
    }

  /* XXX What does this do?  */
  /* updates the log in whatever directory /etc/.safeword contains */
  pblock.mode = UPDATE_LOGS;
  pbmain(&pblock);

  return(ret);
}

/********************************************************************/
int enig_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (enigma_initialized)
    enig_cleanup(user,acode);

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for Enigma authenticator, user %s (denied)", user);

  return(AUTH_FAIL);
}

/********************************************************************/
int enig_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);

  return(AUTH_ERROR);
}

/********************************************************************/
void enig_cleanup(char *user, char *acode)
{
#if ENIGMA_AUTH == 3
  /* 
   * This function was removed in version 4
   */
  if (enigma_initialized)
    uninitenv();
#endif

  return;
}
#endif /*ENIGMA_AUTH*/



#ifdef SECURID_AUTH

#define SID_ADDVER 512
#define SID_NEWPIN 1024
static int sid_outstanding_pin = 0;

/**********************************************************************/
/*                                                                    */
/*			 SecurID Authentication		      	      */
/*                                                                    */
/**********************************************************************/
int sid_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  if (sid_outstanding_pin)
    sid_cleanup(user,acode);

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NOECHO_INPUT;

  sprintf(outbuf->str,"Enter Passcode");

  return(AUTH_SUCCEED);
}

/*
 * This is very stupid of SecurID--since we don't (can't?) use it
 * we should not have to declare it--especially as a GLOBAL
 * which does not have a unique prefix
 */
union config_record configure;
static struct SD_CLIENT sid_sd_dat;

/********************************************************************/
int sid_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  int stat;

  if (sid_outstanding_pin)
    sid_cleanup(user,acode);

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  memset(&sid_sd_dat, 0, sizeof(sid_sd_dat)); /* clear struct */
  creadcfg();			/* init server communication */

  if (sd_init(&sid_sd_dat))
    {
      sprintf(bs_auth_extended,"Cannot initialize SecurID client-server communications");
      return(AUTH_ERROR);
    }

  sos_rip(user);
  sos_rip(inbuf->str);

  stat = sd_check(inbuf->str, user, &sid_sd_dat);

  switch (stat)
    {
    case ACM_OK:
      return AUTH_SUCCEED;

    case ACM_ACCESS_DENIED:
      sprintf(bs_auth_extended,"SecurID denied access");
      return AUTH_FAIL;

    case ACM_NEXT_CODE_REQUIRED:
      /* XXX - need to go into state engine */
      sprintf(bs_auth_extended,"SecurID requires additional code to verify user %s",user);
      sprintf(outbuf->str,"Additional code verification required.");
      *nextstate = SID_ADDVER;
      return AUTH_FAIL;

    case ACM_NEW_PIN_REQUIRED:
      /* XXX - need to go into state engine */
      sprintf(bs_auth_extended,"User %s needs to initialize his PIN",user);
      sprintf(outbuf->str,"New SecurID PIN required");
      *nextstate = SID_NEWPIN;
      sid_outstanding_pin = 1;
      return AUTH_FAIL;

    default:
      sprintf(bs_auth_extended,"UNKNOWN SECURID RETURN CODE for user %s",user);
      return AUTH_ERROR;
    }
  
  return AUTH_ERROR;
}

/********************************************************************/
int sid_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (sid_outstanding_pin)
    sid_cleanup(user,acode);

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for SID authenticator, user %s (denied)",user);

  return(AUTH_FAIL);
}

/********************************************************************/
int sid_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  static char newpin[LENMAXPIN+1];

  memset(outbuf->str, 0, outbuf->len);

  sos_rip(user);
  sos_rip(inbuf->str);

  switch(*nextstate)
    {
      /************************************************************/
      /*            Additional verification required              */
      /************************************************************/

    case SID_ADDVER:
      sprintf(outbuf->str,"If this fails (due to protocol problems outside of brimstone's control)");
      (*nextstate)++;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);
    case SID_ADDVER+1:
      sprintf(outbuf->str,"try logging in via telnet or see your network administrator");
      (*nextstate)++;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);
    case SID_ADDVER+2:
      sprintf(outbuf->str,"----");
      (*nextstate)++;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);
    case SID_ADDVER+3:
      sprintf(outbuf->str,"Please enter your NEXT CARDCODE (do NOT enter your PIN)");
      (*nextstate)++;
      *req_input = BS_SIMPLE_INPUT;
      return(AUTH_FAIL);
    case SID_ADDVER+4:
      (*nextstate) = 0;
      *req_input = BS_NO_INPUT;
      if (sd_next(inbuf->str,&sid_sd_dat) == ACM_OK)
	{
	  sprintf(outbuf->str,"SecurID resyncronized");
	  return(AUTH_SUCCEED);
	}
      else
	{
	  sprintf(bs_auth_extended, "Invalid NEXT CARDCODE verification (user %s)",user);
	  return(AUTH_FAIL);
	}

      /************************************************************/
      /*                        New PIN Mode                      */
      /************************************************************/

    case SID_NEWPIN:
      sprintf(outbuf->str,"If this fails (due to protocol problems outside of brimstone's control)");
      (*nextstate)++;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);
    case SID_NEWPIN+1:
      sprintf(outbuf->str,"try logging in via telnet or see your network administrator");
      (*nextstate)++;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);
    case SID_NEWPIN+2:
      sprintf(outbuf->str,"----");
      (*nextstate)++;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);
    case SID_NEWPIN+3:
      if (sid_sd_dat.user_selectable)
	*nextstate = SID_NEWPIN+16;
      else
	*nextstate = SID_NEWPIN+32;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);

      /* User assigned NEW PIN */
    case SID_NEWPIN+16:
      {
	char *pintype;
	char pinsize[16];

	if (sid_sd_dat.alphanumeric)
	  pintype = "characters";
	else
	  pintype = "digits";

	if (sid_sd_dat.min_pin_len == sid_sd_dat.max_pin_len)
	  sprintf(pinsize,"%d",sid_sd_dat.min_pin_len);
	else
	  sprintf(pinsize,"%d to %d",sid_sd_dat.min_pin_len,sid_sd_dat.max_pin_len);
	  
	sprintf(outbuf->str,"Enter your new PIN containing %s %s",pinsize,pintype);
      }
      (*nextstate)++;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);
    case SID_NEWPIN+17:
      sprintf(outbuf->str,"(or press return for one to be selected for you)");
      (*nextstate)++;
      *req_input = BS_SIMPLE_INPUT;
      return(AUTH_FAIL);
    case SID_NEWPIN+18:
      if (! isalnum(inbuf->str[0]))
	{
	  (*nextstate) = SID_NEWPIN+32;
	  *req_input = BS_NO_INPUT;
	  return(AUTH_FAIL);
	}

      strncpy(newpin, inbuf->str, LENMAXPIN);
      (*nextstate) = SID_NEWPIN+48;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);

      /* System assigned NEW PIN */
    case SID_NEWPIN+32:
      strncpy(newpin, sid_sd_dat.system_pin, LENMAXPIN);
      sprintf(outbuf->str,"New pin is:  %s",newpin);
      (*nextstate)++;
      *req_input = BS_NO_INPUT;
      return(AUTH_FAIL);
    case SID_NEWPIN+33:
      sprintf(outbuf->str,"Please press return after you have memorized your new PIN");
      (*nextstate) = SID_NEWPIN+48;
      *req_input = BS_SIMPLE_INPUT;
      return(AUTH_FAIL);

      /* Actually assign PIN */
    case SID_NEWPIN+48:
      (*nextstate) = 0;
      *req_input = BS_NO_INPUT;
      sid_outstanding_pin = 0;
      if (sd_pin(newpin, 0, &sid_sd_dat) == ACM_NEW_PIN_ACCEPTED)
	{
	  sprintf(outbuf->str,"New PIN accepted");
	  return(AUTH_SUCCEED);
	}
      else
	{
	  sprintf(outbuf->str,"New PIN rejected");
	  return(AUTH_FAIL);	/* Should we deny access because of invalid PIN assignment? */
	}

    default:
      sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);
      *nextstate = 0;
      *req_input = BS_NO_INPUT;
      return(AUTH_ERROR);
    }

  sprintf(bs_auth_extended, "ERROR: invalid exit from state engine (%d)", *nextstate);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;
  return(AUTH_ERROR);
}

/********************************************************************/
void sid_cleanup(char *user, char *acode)
{

  if (sid_outstanding_pin)
    {
      sid_outstanding_pin = 0;
      sd_pin("", 1, &sid_sd_dat);
    }
  return;
}
#endif /*SECURID_AUTH*/


#ifdef CCARD_AUTH
/**********************************************************************/
/*                                                                    */
/*		      CryptoCard Authentication			      */
/*                                                                    */
/**********************************************************************/

static unsigned int cur_ccard_challenge;
extern void ccard_calcResp( char *key, char *challenge, char *response, u_char *binaryResponse );


int ccard_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  int count = 0;

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }

  cur_ccard_challenge = 1<<31;
  while (cur_ccard_challenge > 99999999) /* We only can enter 8 decimal bytes */
    {
      sos_get_rand((unsigned char *)&cur_ccard_challenge, sizeof(cur_ccard_challenge));
      cur_ccard_challenge &= ((1<<27) - 1);

      if (++count > 10)
	{
	  cur_ccard_challenge &= ((1<<26) - 1);
	  soslog(SOSLOG_NOTICE,SOSLOG_TYPE_CONDITION,SOSLOG_NO_PERROR,"Is there an infinite probablility drive in operation?");
	}
    }

  sprintf(outbuf->str,"Challenge:  %08d",cur_ccard_challenge);

  return(AUTH_SUCCEED);
}

/********************************************************************/
int ccard_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  char string_challenge[9];
  char string_resp[9];
  unsigned char binaryResponse[8];

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sos_rip(inbuf->str);

  sprintf(string_challenge, "%08d", cur_ccard_challenge);
  ccard_calcResp(acode, string_challenge, string_resp, binaryResponse);

  if (!strcasecmp(string_resp, inbuf->str))
    return AUTH_SUCCEED;
  return AUTH_FAIL;
}

/********************************************************************/
int ccard_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  /* XXX - Should keyinit */
  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for CCARD authenticator, user %s (denied)", user);

  return(AUTH_FAIL);
}

/********************************************************************/
int ccard_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);

  return(AUTH_ERROR);
}

/********************************************************************/
void ccard_cleanup(char *user, char *acode)
{
  return;
}
#endif /*CCARD_AUTH*/


#ifdef HASH_STATIC_AUTH
/**********************************************************************/
/*                                                                    */
/*		     SOS's Static hash Authentication		      */
/*                                                                    */
/**********************************************************************/

int hash_static_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NOECHO_INPUT;

  sprintf(outbuf->str, "Please enter password");

  return(AUTH_SUCCEED);
}

/********************************************************************/
int hash_static_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  unsigned char salt[4];
  unsigned char *key;

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sos_rip(inbuf->str);

  memcpy(salt,acode,sizeof(salt));
  key = sos_statichash(salt,inbuf->str);

  if (!strcmp(key, acode))
    return AUTH_SUCCEED;
  return AUTH_FAIL;
}

/********************************************************************/
int hash_static_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  /* XXX - Should keyinit */
  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for HASH_STATIC authenticator, user %s (denied)", user);

  return(AUTH_FAIL);
}

/********************************************************************/
int hash_static_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);

  return(AUTH_ERROR);
}

/********************************************************************/
void hash_static_cleanup(char *user, char *acode)
{
  return;
}
#endif /*HASH_STATIC_AUTH*/


#ifdef HASH_DYNAMIC_AUTH
/**********************************************************************/
/*                                                                    */
/*		      SOS's Dynamic HASH Authentication		      */
/*                                                                    */
/**********************************************************************/

static unsigned char cur_hash_dynamic_challenge[8];


int hash_dynamic_challenge(char *user, char *acode, u_int *nextstate, u_int *req_input,
		   sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_SIMPLE_INPUT;

  sos_get_rand(cur_hash_dynamic_challenge, sizeof(cur_hash_dynamic_challenge));

  sprintf(outbuf->str,"Challenge: %08X %08X",*((int *)(&(cur_hash_dynamic_challenge[0]))),*((int *)(&(cur_hash_dynamic_challenge[4]))));

  return(AUTH_SUCCEED);
}

/********************************************************************/
int hash_dynamic_auth(char *user, char *acode, u_int *nextstate, u_int *req_input,
	      sos_string *outbuf, sos_string *inbuf)
{
  unsigned int invar1;
  unsigned int invar2;
  unsigned char in_testbuf[18];
  unsigned char *tmp;
  unsigned char out_testbuf[18];

  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  /* Find what the user thinks the hash is */
  sos_rip(inbuf->str);
  sscanf(inbuf->str,"%08X %08X",&invar1, &invar2);
  sprintf(in_testbuf,"%08X %08X",invar1,invar2);

  /* Find what I think the hash should be */
  tmp = sos_dynamichash("",cur_hash_dynamic_challenge,acode);
  sprintf(out_testbuf,"%08X %08X",*((unsigned int *)(tmp)),*((unsigned int *)(tmp+4)));

  if (!strcasecmp(in_testbuf,out_testbuf))
    return AUTH_SUCCEED;
  return AUTH_FAIL;
}

/********************************************************************/
int hash_dynamic_passwd(char *user, char *acode, u_int *nextstate, u_int *req_input,
		sos_string *outbuf, sos_string *inbuf)
{
  if (outbuf->len < BS_IOLEN)
    {
      sprintf(bs_auth_extended, "Output buffer size is too small (%d < %d)",outbuf->len, BS_IOLEN);
      return(AUTH_ERROR);
    }
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  /* XXX - Should keyinit */
  sprintf(outbuf->str, "Permission Denied");
  sprintf(bs_auth_extended, "Password change request for HASH_DYNAMIC authenticator, user %s (denied)", user);

  return(AUTH_FAIL);
}

/********************************************************************/
int hash_dynamic_state(char *user, char *acode, u_int *nextstate, u_int *req_input,
	       sos_string *outbuf, sos_string *inbuf)
{
  memset(outbuf->str, 0, outbuf->len);
  *nextstate = 0;
  *req_input = BS_NO_INPUT;

  sprintf(bs_auth_extended, "ERROR: invalid entry into state engine (%d)", *nextstate);

  return(AUTH_ERROR);
}

/********************************************************************/
void hash_dynamic_cleanup(char *user, char *acode)
{
  return;
}
#endif /*HASH_DYNAMIC_AUTH*/



