/*--------------------------------------------------------------------------
                            S I C S   T E L N E T

  Implementation of the telnet task things for SICS. The actual telnet
  protocoll handling lives in nread.c.
  
  coyright: see copyright.h
  
  Mark Koennecke, January 1998
----------------------------------------------------------------------------*/
#include <time.h>
#include "sics.h"
#include "passwd.h"
#include "telnet.h"
#include "fortify.h"
#define LOGINWAIT  300 
/* 300 == 5 minutes to wait for valid username password */
/*-------------------------------------------------------------------------*/
   typedef struct __TelTask {
                             SConnection *pCon;
                             int iLogin;
                             char pLoginWord[132];
                             time_t tStart;
                           } TelTask;
/*--------------------------------------------------------------------------*/
   pTelTask CreateTelnet(SConnection *pCon)
   {
      pTelTask pRes = NULL;
      char *pPtr = NULL;
      time_t shit;
      assert(pCon);
      
      /* check for the login word */
      pPtr = IFindOption(pSICSOptions,"TelWord");
      if(!pPtr)
      {
        return NULL;
      }
      pRes = (pTelTask)malloc(sizeof(TelTask));
      if(!pRes)
      {
        return NULL;
      }
      
      /* initialise */
      memset(pRes,0,sizeof(TelTask));
      pRes->pCon = pCon;
      pRes->iLogin = 0;
      pRes->tStart = time(&shit);
      strcpy(pRes->pLoginWord,pPtr);
      return pRes;
   }
/*--------------------------------------------------------------------------*/
   void DeleteTelnet(void *pData)
   {
      pTelTask pKill = NULL;
      assert(pData);
      
      pKill = (pTelTask)pData;
      
      if(pKill->pCon)
      {
        SCDeleteConnection(pKill->pCon);
      }
      free(pKill);
   }   
/*-------------------------------------------------------------------------*/
  static void SendWelcome(SConnection *pCon)
  {
    SCWrite(pCon,"--------- Welcome to SICS ------------",eError);
    SCWrite(pCon,"You are now connected to a SICS Instrument Control Server",eError);
    SCWrite(pCon,"\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",eError);
    SCWrite(pCon,"WARNING: Proceed with utmost care!",eError);
    SCWrite(pCon,"YOU MAY BE MOVING HARDWARE IN THE EXPERIMENT HALL",eError);
    SCWrite(pCon,"YOU MAY CAUSE GRIEVIOUS BODILY HARM TO SOMEBODY",eError);
    SCWrite(pCon,"YOU MAY DAMAGE VALUABLE AND SOMETIMES IRREPLACABLE HARDWARE",
            eError);
    SCWrite(pCon,"Continuing here seriously compromises hacker's ethics",eError);
    SCWrite(pCon,"You will NOT find valuable data here!",eError);
    SCWrite(pCon,"The SICS server does NOT allow you to spawn to the system",eError);
    SCWrite(pCon,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",eError);        
  }   
/*-------------------------------------------------------------------------*/
  static void SendGA(SConnection *pCon)
  {
    char pReply[2];
    
    pReply[0] = (char)255;
    pReply[1] = (char)249;
    NETWrite(pCon->pSock,pReply,2);
  }  
/*--------------------------------------------------------------------------*/
   int TelnetTask(void *pData)
   {
      pTelTask self = NULL;
      char *pPtr = NULL;
      char *pLogin = NULL;
      char *pUser = NULL, *pPasswd = NULL;
      char pBuffer[512];
      int iRet;
      time_t shit;
      
      self = (pTelTask)pData;
      assert(self);
      
      if(self->pCon->iEnd)
      {
        if(self->pCon->inUse > 0)
	{
          return 1;
        }
        else
	{
           return 0;
        }
      }
      
      /* pop and execute */
      iRet = CostaPop(self->pCon->pStack,&pPtr);
      if(iRet)
      {
          if(pPtr)
          {
           if(self->iLogin) /* handle normal command */
           {
              /* check for logoff */
              if(strstr(pPtr,"logoff") != NULL)
              {
                NetReadRemove(pServ->pReader,self->pCon->pSock);
                free(pPtr);
                self->pCon->iEnd = 1;
                return 0;
              }
              /* invoke command */
              CostaLock(self->pCon->pStack);
              SCInvoke(self->pCon,self->pCon->pSics,pPtr);
              CostaUnlock(self->pCon->pStack);
              SendGA(self->pCon);
              free(pPtr);
           }  
           else  /* handle login messages */
           {
             pLogin = strstr(pPtr,self->pLoginWord);
             if(!pLogin)
             {
                SCWrite(self->pCon,
                "------------------- Get Lost -------------------",
                 eError);
                if(time(&shit) > self->tStart + LOGINWAIT)
                {
                  SCWrite(self->pCon,
                          "I cannot stand your login attempts anymore!",
                          eError);
                  NetReadRemove(pServ->pReader,self->pCon->pSock);
                  self->pCon->iEnd = 1;
                  free(pPtr);
                  return 0;        
                } 
                free(pPtr);
                return 1;       
             }
             else /* check username / password */
             {
               pLogin += strlen(self->pLoginWord);
               pUser = strtok(pLogin," \t");
               pPasswd = strtok(NULL," \t\r\n"); 
               iRet = IsValidUser(pUser,pPasswd);
               if(iRet < 0)
               {
                   sprintf(pBuffer,"SYSTEM ATTACK by %s / %s",pUser,
                          pPasswd);
                   SICSLogWrite(pBuffer,eInternal);
                   SCWrite(self->pCon,
                     "I do not know you, I do not let you in",eError);
                   SendGA(self->pCon);
                   free(pPtr);
                   return 1;
               } 
               else
               {
                 SendWelcome(self->pCon);
                 SCSetRights(self->pCon,iRet);
                 self->iLogin = 1;
                 SendGA(self->pCon);
                 free(pPtr);
                 return 1;
               }
            }
           }
          } 
      }
      /* check for no commands but timeout on telnet */
      if( !self->iLogin && (time(&shit) > self->tStart + LOGINWAIT) )
      {
        self->pCon->iEnd = 1;
        NetReadRemove(pServ->pReader,self->pCon->pSock);
        return 0;
      }
      
      
      /* check for end */  
      if(self->pCon->iEnd)
      {
        if(self->pCon->inUse > 0)
	{
          return 1;
        }
        else
	{
           return 0;
        }
      }
      
      return 1;
   }
/*---------------------------------------------------------------------------*/
   void TelnetSignal(void *pData, int iSignal, void *pSigData)
   {
     pTelTask self = NULL;
     int *iInt;
     char *pPtr;
     
     self = (pTelTask)pData;
     assert(self);
     
     if(iSignal == SICSINT)
     {
       iInt = (int *)pSigData;
       SCSetInterrupt(self->pCon,*iInt);
       if(*iInt == eEndServer)
       {
         self->pCon->iEnd = 1;
       }
     }
     else if(iSignal == SICSBROADCAST)
     {
       pPtr = (char *)pSigData;
       if(pPtr)
       {
         SCWrite(self->pCon,pPtr,eWarning);
       }
     }
     else if(iSignal == TOKENRELEASE)
     {
       self->pCon->iGrab = 0;
     }
     else if(iSignal == TOKENGRAB)
     {
       self->pCon->iGrab = 1;
     }
   }  
/*-------------------------------------------------------------------------*/
   static mkChannel *pTelnet = NULL;
   
   void InstallTelnet(void)
   {
     char *pPtr = NULL;
     int i, iPort;

     /* No double telnet ports ! */     
     assert(!pTelnet);
     
     /* if the option is not there or invalid, telnet is disabled */
     pPtr = IFindOption(pSICSOptions,"TelnetPort");
     if(!pPtr)
     {
       return;
     }
     i = sscanf(pPtr,"%d",&iPort);
     if(i > 0)
     {
       pTelnet = NETOpenPort(iPort);
     }  
     
     /* when we have a port have the NetReader listen and handle it */ 
     if(pTelnet)
     {
       NetReadRegister(pServ->pReader,pTelnet, taccept, NULL);
     }
   }
/*---------------------------------------------------------------------------*/
   void KillTelnet(void)
   {
     if(pTelnet)
     {
       NETClosePort(pTelnet);
/*       NetReadRemove(pServ->pReader,pTelnet); */
       free(pTelnet);
       pTelnet = NULL;
     }
   }

