#include <stdio.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <des.h>
#include "inet.h"
#include <krb.h>
#include <krb_err.h>
 
#include "esdefs.h"
 
/*  This is a test client program */
 
 
/* GLOBALS  -- Ughh */
int           sock;
char          wall_1[3];
char          dbuf       [SBUFLEN];
char          wall_2[3];
char          header_buf [HDR_SIZE];
char          receive_buf[SBUFLEN];
int           read_start_enc, read_length;
int           debug = 1;
 
/***************/
/* DES globals */
/***************/
des_cblock    key;
Key_schedule  key_schd;
#define       DES_BUFLEN 1024
unsigned char ivec[DES_BUFLEN];
/* des_cblock    *ivec; */
char          ebc_str[30];
long          des_len;   

/* #define USE_KERBEROS 1 */
 
/* Prototypes */                        /* dmh */
void do_quit (void);                    /* dmh */
void decrypt_msg (void);                /* dmh */
char *get_msg (void);                   /* dmh */
int get_login_info (char *, char *);    /* dmh */
long es_auth (char *, char *);          /* dmh */
 
char    *
next_field(char **ptr)

{
        register char  *cp = *ptr;
 
        while (*cp != NULL && *cp != DLM)
                cp++;
        if (*cp == NULL)  /* end of the string */
            return (*ptr = cp);
 
        *cp = '\0';
        return (*ptr = ++cp);
}

/*********************************/ 
/* Initialize connection routine */
/*********************************/ 
init_conn()
{
int i;
    /* open connection  */
    sock = inet_establish_connection(ES_OPEN ,ES_PORT, 0);
    if (sock < 0) {
	puts("Fatal error: could not establish connection.");
	exit(sock);
    }
    get_msg();
    printf("banner=%s\n",receive_buf);
    return;
}
 
/**********************************************************************/
/* Get login information routine.                                     */
/**********************************************************************/
int get_login_info (char *local_userid, char *passwd) {
 
    char prompt[15];
    int rc, max, verify;
 
    /* Get login information.                                dmh */
    printf ("login: ");       /* Get user's login name for now. */
    fflush (stdout);
    gets (local_userid);
   /*  if (strncmp (local_userid,"esandi",6) )
       return (-1); while we test kerberos */
 
    strcpy (prompt,"Password: ");
    max = 512;
    verify = 0;
 
    rc = des_read_pw_string (passwd, max, prompt, verify);
    if (rc != 0) {
       printf ("Error in des_read_pw_string!\n");
       return (rc);
     }
 
    return (0);
}
 


/********************/ 
/* send_msg routine */
/********************/ 

send_msg(tisock,str,len)
int tisock;
char *str;
int len;
{
int wrote;
char msg[SBUFLEN];
 
sprintf(msg,"%s%s",str,CRLF);
wrote = write(tisock,str,len + 2);
/* printf("wrote %d\n",wrote);
/* printf("wrote end %d\n",wrote); */
}


/********************/ 
/* do_quit routine. */
/********************/ 

void do_quit() {    /* dmh */
   printf ("do_quit: Communication with server finished.\n");
   exit (-1);
 }


/********************/ 
/* get_msg routine. */
/********************/ 
 
char *get_msg()  /* common read routine, uses global buffer */
{
        int  rc,cnt=0;
        char junk[BUFSIZ];
        int  debug = 0;

        bzero (ivec, sizeof(ivec));
        des_len    = 0;

        /* Read the header into a separate buffer. */
        bzero (header_buf, HDR_SIZE);
        rc = read (sock, header_buf, HDR_SIZE);
        if (rc < 0) {
           printf ("get_msg: Could not read header!\n");
           do_quit();
        }
 
        /* Get loc at which to start decryption or -1 for none. */
        sscanf (header_buf, "%d %d",&read_start_enc,&read_length);

        bzero (header_buf, HDR_SIZE);

        if (debug == 1) {
           printf ("get_msg: read_start_enc= %d\n",read_start_enc);
           printf ("get_msg: read_length   = %d\n",read_length);
        }

        do {
           if (debug) {   
              printf ("get_msg: top of do loop\n");
              printf ("get_msg: bytes req=%d\n",SBUFLEN-des_len);
           } 

           if (des_len == 0)
              bzero (receive_buf, SBUFLEN);

 
           rc = read(sock, &receive_buf[des_len], SBUFLEN - des_len);

           if (debug)   
              printf ("get_msg: req=%d, read=%d\n",SBUFLEN-des_len,rc);
            
           if (rc == 0)
              cnt++;
           if (cnt > 50) /* don't keep reading nothing, somethings
                             wrong, exit */
              do_quit();
           if (rc < 0 )
              do_quit(); /* perror("in read"); */
           else
              des_len = rc + des_len;
 
           /* Check what ended the read and act accordingly. */
           if (des_len >= SBUFLEN) {
              printf ("\nBuffer filled, des_len = <%d>\n",des_len); 
              decrypt_msg();
           }
 
           if (terminator(&receive_buf[des_len-EOM_LEN] )) {
              printf ("get_msg: Read ended by terminator!\n");

              /* Remove End Of Message indicator */ 
              des_len -= EOM_LEN;
 
              /* Remove trailing CR or LF stuck in by server. */
              if (receive_buf[des_len - 1] == LF)
              des_len--;

              if (receive_buf[des_len - 1] == CR)
              des_len--;

              receive_buf[des_len] = '\0';
              /* printf ("Set receive_buf[%d] to null\n",des_len); */
              decrypt_msg();

              break;
           }
        } while (!terminator(&receive_buf[des_len-EOM_LEN])); 

        return receive_buf;                                    
}


/*************************************************/ 
/* Decrypt (if necessary) and print the message. */
/*************************************************/ 

void
decrypt_msg()
{
   int i;
static   int notfirst = 0;
unsigned long *iv;
unsigned char tmp[8];
strcpy (tmp,"VVVVVV");
iv = tmp;
   if (read_start_enc == -1)        /* -1 means non-encrypted message. */
      printf("<%s>\n",receive_buf); 

   else {
      /* Decrypt the current buffer. */
/*      printf ("des_cbc_encrypt, doing <%d> bytes\n",des_len); */

if ((long)iv &3)
  printf("got\n");

if (notfirst)
      des_cbc_encrypt (receive_buf, dbuf, des_len, key_schd, 
                       iv, DES_DECRYPT);
else
      des_cbc_encrypt (receive_buf, dbuf, des_len, key_schd, 
                       ivec, DES_DECRYPT);

      printf ("ivec=<%d><%d><%d>\n", (int)ivec[1],(int)ivec[2],(int)ivec[3]);

      fflush (stdout);

      /* Move to next buffer if necessary */
      /* move_to_next_buffer (BUF); */

      /* For now, reset the single buffer */
      des_len = 0;
 notfirst++;
   }  
 printf("%s",dbuf);
}

 
/************************************/
/* Kerberos authentication routine. */
/************************************/

long es_auth (char *user, char *password) {
 
   long code = 0L,status;
   char tosend[4*BUFSIZ], torecv[BUFSIZ],astr[BUFSIZ];
   char *ptr, *cp;
 
   int sendlength;
   int ES_DEBUG = 0;
 
   KTEXT_ST ktxt;
   char pinst[INST_SZ], prealm[REALM_SZ];
   unsigned long checksum_sent, checksum_returned;
 
   char short_name[INST_SZ];
   char  tmp_krbtkfile[100];
   strcpy (pinst, (char *) krb_get_phost(ES_SERVER));
   strcpy (prealm, (char *) krb_realmofhost (ES_SERVER));
 
   /********************************************************************/
   /* On MAC & DOS probably have to do something like this, because we */
   /*   don't have a TGT yet                                           */
   /********************************************************************/
 
   /* because get_pw_in_tkt does not accept a fully qualified name ... */
   strncpy(short_name,krb_get_phost(ES_SERVER), INST_SZ);
   if (ES_DEBUG) {
      printf("realm = <%s>\n",prealm);
      printf ("service = %s, server = <%s>\n",ES_SERVICE,short_name);
   }
 
   sprintf (tmp_krbtkfile, "/tmp/tkt_%d", getpid ());
   krb_set_tkt_string (tmp_krbtkfile);  /* set tmp tkt file */
 
   status = krb_get_pw_in_tkt (user, "", prealm,
			       ES_SERVICE, short_name, 1, password);
 
   if (status != 0) {
      printf ("Error in Kerberos login/password\n");
      exit (status);
    }
 
   if (ES_DEBUG)
      printf ("status after get_pw_in_tkt = %d\n", status);
 
   /***********************************************************/
   /* On ATHENA USE THIS METHOD because we already have a TGT */
   /***********************************************************/ 
   code = (long) krb_mk_req (&ktxt, ES_SERVICE,
			     pinst, prealm,
			     checksum_sent= (unsigned long) random());
 
   if (code) {
     printf("KERBEROS ERROR: %s.%s@%s - %s", ES_SERVICE, pinst, prealm,
	    krb_err_txt[code]);
     return (code+ERROR_TABLE_BASE_krb);
   }
 
   /* construct command */
   sprintf (tosend, "K:%d:", ktxt.length);
/*   sprintf (tosend, "P:%d:", ktxt.length);  */
 
   if (ES_DEBUG)
      printf ("es_auth: ktxt.length=%d\n",ktxt.length);
 
   sendlength = strlen (tosend);
   bcopy (ktxt.dat, tosend+sendlength, ktxt.length);
 
   if (ES_DEBUG)
      printf ("es_auth: ktxt.dat=<%s>\n",ktxt.dat);
 
   tosend[sendlength+ktxt.length] = '\0';
   sendlength += ktxt.length + 1;
 
   /* Send command and receive reply */
   bzero (receive_buf, SBUFLEN);
   send_msg(sock,tosend,sendlength);
   get_msg();
 
   printf ("es_auth: message back from Kerberos = <%s>\n",receive_buf);
   return;
 }



/****************/ 
/* Main program */
/****************/ 

main(int argc, char **argv)
{
char   transline[200], *cp;
int    rc, i;
 
char passwd[9];
struct trans_struct {
   char local_userid[9];
   char trans_type[5];
   char trans_data[20];
} transaction;
 
/********************/
/* For krb_get_cred */
/********************/
char *instance = "mitvmc";
char *realm    = "ATHENA.MIT.EDU";
char service[5];
extern char *msglist[];        /* The list of error messages */
CREDENTIALS creds;
 
/* Keep trying until correct local_userid and password entered. */
/* Will be replaced by kerberos login.                    */
printf ("ESANDI Client (test)\n\n");
for (;;) {
   rc = get_login_info (transaction.local_userid, passwd);
   if (rc == 0)
      break;
}
 
init_conn(); /* open connection to server & get banner */
rc = es_auth(transaction.local_userid,passwd);
 
/*********************************/
/* DES decryption initialization */
/*********************************/

/* if ((malloc (ivec, DES_KEY_SZ )) == 0) { 
     printf ("Could not get space for ivec!\n");
     do_quit();
} */

#ifdef USE_KERBEROS
   /* Use Kerberos routine to get the session key. */
   strcpy (service, ES_SERVICE);
   rc = krb_get_cred(service, instance, realm, &creds);
   if (rc != KSUCCESS) {
      printf ("client: krb_get_cred failed!\n");
      printf ("Kerberos error in krb_get_cred:%d:%s",rc,krb_err_txt[rc]);
      exit (rc);
   }
   bcopy (creds.session, key, sizeof (C_Block));
 
#else
   /* Use a test key if we don't have Kerberos. */
   strcpy (ebc_str, "This is a test.");
   des_string_to_key (ebc_str, key);
#endif

des_key_sched (key, key_schd);
 

/********************/
/* Transaction loop */
/********************/

while (TRUE)
  {
    printf("Enter the transaction type: ");
    gets(transaction.trans_type);
    if (strncasecmp(transaction.trans_type,"qq",2) == 0)
      break;
    printf("Enter the 1st parameter: ");
    gets(transaction.trans_data);
    sprintf(transline,"%s:%s", transaction.trans_type,
                               transaction.trans_data);
 
    send_msg(sock,transline,strlen(transline));
    get_msg();                     /* Gets message in dbuf array */
 
  }   /* while (TRUE) */
 
return;
}
