/* example2.c */
/********************************************************/
/* ©1990 - 2000 RSA Security Inc.  All Rights Reserved. */
/********************************************************/

/* example2.c uses sd_pin, sd_check, sd_next  */

/* 
 * This program demonstrates the API by allowing users to 
 * log in, and it handles all the new pin parameters.
 * 
 * This program searches for sdconf.rec in the following location:
 * the path pointed to by the environment variable VAR_ACE defined in 
 * /etc/sdace.txt.
 *
 */
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/param.h>
#include <ctype.h>
#include <stdlib.h>
#include "sdi_athd.h"
#include "sdi_size.h"
#include "sdi_type.h"
#include "sdi_defs.h"
#include "sdconf.h"
#include "sdacmvls.h"

extern void sd_close();

union config_record configure;

#define CANCELLED	1

main()
{
struct SD_CLIENT sd_dat, *sd;
int ret;
char input[64], passcode[LENPRNST + 4];
char inbuf[128];
char inbuf2[128];
char buf[128];
char prompt[256];
char pinsize[20], pintype[20];
char reply[3];
char *c, *p;
int stat, retcode;
char * pszEnvValue; 
FILE * pfdAcefile; 
char szVarAce[256]; 
char * pszVarAce; 
int a1, a2;

pszEnvValue = getenv("VAR_ACE");

if(pszEnvValue == NULL)
{
  pfdAcefile = fopen ("/etc/sdace.txt","r");
  if(pfdAcefile == NULL)
    {
       perror("fopen");
       fprintf(stderr, "error opening /etc/sdace.txt\n");
       exit(2);
     }
   
  fscanf(pfdAcefile, "%s", szVarAce);
  fclose(pfdAcefile);
  
  if (putenv(szVarAce))
    {
      fprintf(stderr, "error on putenv, %s\n", szVarAce);
      exit(2); 
    }
}

memset(&sd_dat, 0, sizeof(sd_dat));   /* clear struct */
sd = &sd_dat;
a1=creadcfg();
if(a1!=0)  /* access sdconf.rec */
{
   fprintf(stderr, "Error reading sdconf.rec.\n");
   exit(1);
}
a2=sd_init(sd);
if (a2!=0) /* initialize socket */
{
   printf("Cannot initialize client-server communications.  \n");
   exit(1);
}
printf("\nenter login: ");

/*  recall that fgets returns the string followed by \n\0,
    so the \n must be removed  */
if (fgets(input, sizeof(input), stdin) == NULL)
     exit(0);
input[strlen(input) - 1] = '\0';

stat = sd_termio("Enter PASSCODE: ", 60, passcode, sizeof(passcode), 
                   SDI_NO_ECHO);
sd_termout("\n");

ret = sd_check(passcode, input, sd);
passcode[stat] = 0;

switch (ret) { case ACM_OK:
	printf("user %s authenticated \n", input);
        break;
   
   case ACM_ACCESS_DENIED:
	printf("access denied for user %s \n", input);
	break;
   
   case ACM_NEXT_CODE_REQUIRED:
	printf("next Tokencode: ");

	stat = sd_termio("Enter PASSCODE: ", 60, passcode, sizeof(passcode), 
                    SDI_NO_ECHO);
	sd_termout("\n");
   
	if (sd_next(passcode, sd) == ACM_OK)
	{
	   printf("Next passcode accepted for user %s \n", input);
	   printf("User authenticated \n");
	}
	else
	{
	   printf("access denied, next Tokencode bad \n");
	}
	break;
   
   case ACM_NEW_PIN_REQUIRED:
	printf("New PIN required; do you wish to continue? (y/n) [n]: ");
	c = fgets(reply, 3, stdin);
	if (strncmp(reply, "y", 1))
 	{
	   sd_pin("", CANCELLED, sd);
	   printf("Cancelled new PIN protocol \n");
	   exit(0);
	}
	if (sd->alphanumeric)
	   strcpy(pintype, "characters");
	else 
	   strcpy(pintype, "digits");
	if (sd->min_pin_len == sd->max_pin_len)
	   sprintf(pinsize, "%d", sd->min_pin_len);
	else 
	   sprintf(pinsize, "%d to %d", sd->min_pin_len, sd->max_pin_len);

        do  /* must get a legitimate PIN */
	{
	   switch (sd->user_selectable)
	   {  
	      case CANNOT_CHOOSE_PIN:
	      sprintf(prompt,
	      "\n\tPress <Return> to generate a new PIN and display it");
	      sprintf(prompt+strlen(prompt),
		      " on the screen,\n\t\t or \n\t<Ctrl d> to cancel ");
	      sprintf(prompt+strlen(prompt),
		      "the New PIN procedure: ");
	      return( sysPINverify( prompt, inbuf, sizeof(inbuf), sd, &stat));
	      
	      case USER_SELECTABLE:
	      sprintf(prompt, "\n\tEnter your new PIN, containing %s %s,\n", 
		      pinsize, pintype);
	      sprintf(prompt+strlen(prompt),
		      "\t\t or \n\t<Return> to generate a new PIN and");
	      sprintf(prompt+strlen(prompt),
		      " display it on the screen,\n\t\t or \n\t<Ctrl d>");
	      sprintf(prompt+strlen(prompt),
		      " to cancel the New PIN procedure: ");
	      retcode = sysPINverify(prompt, inbuf, sizeof(inbuf), sd, &stat);
	      
	      if (retcode == ACM_ACCESS_DENIED)
		 return ( ACM_ACCESS_DENIED);
	      /*  end of blank return case  */
	      break;
	      
	      case MUST_CHOOSE_PIN:
	      sprintf(prompt, "\n\tEnter your new PIN, containing %s %s,\n",
		      pinsize, pintype);
	      sprintf(prompt+strlen(prompt),
	      "\t\t or \n\t<Ctrl d> to cancel the New PIN procedure: ");
	      stat = sd_termio(prompt, 30, inbuf, sizeof(inbuf), SDI_NO_ECHO);
	      if (stat <= 0)  /* user typed ^D */
	      {
		 sd_pin("", CANCELLED, sd);  /* tell server it is cancelled */
		 sd_termout("Access Denied\n");
		 return(ACM_ACCESS_DENIED);
	      }
	      break;
	      
	      default:
	      break;
	   }  /* End of switch (sd->user_selectable) */
	   /*  end of new PIN required  */
	   for (p = inbuf; (*p = tolower(*p)); p++);        /* tolower loop */
	}  while (!(check_pin(inbuf, sd)));
     
	stat = sd_termio("\n\nPlease re-enter new PIN: ", 30, inbuf2,
            sizeof(inbuf2), SDI_NO_ECHO);
 
	for (p = inbuf2; (*p = tolower(*p)); p++);       /* tolower loop */
	  if ((stat == EOF) ||  (stat != strlen(inbuf))
	      || (memcmp(inbuf, inbuf2, stat)))
	  {
	     sd_termout("\nPINs do not match. Please try again.\n");
	     sd_pin("", CANCELLED, sd);  /* tell server its cancelled */
	     return (ACM_ACCESS_DENIED);
	  }
	if ((retcode = sd_pin(inbuf, 0, sd)) == ACM_NEW_PIN_ACCEPTED)
	   sd_termout("\n\nWait for the code on your token to change, then run example2 with the new PIN\n");
	else
	{
	   sd_termout("\n\nPIN rejected. Please try again.\n");
	}
	return (ACM_ACCESS_DENIED);
   
   default:
	printf("unknown return code %d \n", ret);
	strcpy(buf, "Access Denied\n");
	sd_termout(buf);
	return ACM_ACCESS_DENIED;
   
   break;
   
}		/* switch on ret from sd_check  */
sd_close();	/* Shutdown the network connection */
exit(0);
}






