From 6c1059b30716beda79e921f9cb85a10805fd9c7e Mon Sep 17 00:00:00 2001 From: koennecke Date: Wed, 2 Nov 2016 15:08:53 +0100 Subject: [PATCH] First completed version of cleaned up connection object. First testing is promising --- conman.c | 37 ++++- conman.h | 7 +- nread.c | 497 ++++--------------------------------------------------- telnet.c | 32 ++-- 4 files changed, 86 insertions(+), 487 deletions(-) diff --git a/conman.c b/conman.c index 13985832..93a76331 100644 --- a/conman.c +++ b/conman.c @@ -2349,7 +2349,7 @@ int SCGetRunLevel(SConnection *pCon) return pCon->runLevel; } /*--------------------------------------------------------*/ -int SCGetIdent(SConnection *pCon) +long SCGetIdent(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; @@ -2404,7 +2404,14 @@ char *SCGetDeviceID(SConnection *pCon) } return pCon->deviceID; } - +/*-------------------------------------------------------*/ +int SCGetEnd(SConnection *pCon) +{ + if (!VerifyConnection(pCon)) { + return 0; + } + return pCon->iEnd; +} /*-------------------------------------------------------*/ void SCSetConStatus(SConnection *pCon, int conStatus) { @@ -2476,4 +2483,28 @@ void SCSetGrab(SConnection *pCon, int iGrab) } pCon->iGrab = iGrab; } - +/*------------------------------------------------------------*/ +void SCSetEnd(SConnection *pCon, int val) +{ + if (!VerifyConnection(pCon)) { + return; + } + pCon->iEnd = val; +} +/*------------------------------------------------------------*/ +void SCSetTelnet(SConnection *pCon, int val) +{ + if (!VerifyConnection(pCon)) { + return; + } + pCon->iTelnet = val; +} +/*------------------------------------------------------------*/ +void SCClose(SConnection *pCon) +{ + if (!VerifyConnection(pCon)) { + return; + } + ANETclose(pCon->sockHandle); + pCon->iEnd = 1; +} diff --git a/conman.h b/conman.h index 4492c426..f1f5a572 100644 --- a/conman.h +++ b/conman.h @@ -86,6 +86,7 @@ SConnection *SCfindMaster(SConnection * pCon); int SCisConnected(SConnection * pCon); int VerifyConnection(SConnection * pCon); int SCVerifyConnection(SConnection * self); +void SCClose(SConnection *pCon); /*------------------------------- tasking --------------------------------*/ int SCTaskFunction(void *pCon); void SCSignalFunction(void *pCon, int iSignal, void *pSigData); @@ -141,20 +142,22 @@ int SCGetOutClass(SConnection * self); int SCGetGrab(SConnection * pCon); int SCActive(SConnection * pCon); int SCGetRunLevel(SConnection *pCon); -int SCGetIdent(SConnection *pCon); +long SCGetIdent(SConnection *pCon); int SCGetSicsError(SConnection *pCon); int SCGetTransID(SConnection *pCon); int SCGetProtocolID(SConnection *pCon); int SCGetSockHandle(SConnection *pCon); int SCGetConStatus(SConnection *pCon); char *SCGetDeviceID(SConnection *pCon); +int SCGetEnd(SConnection *pCon); /************************* connection parameter change **********************/ void SCSetConStatus(SConnection *pCon, int conStatus); void SCSetEventType(SConnection *pCon, int eventType); void SCSetSicsError(SConnection *pCon, int sicsError); void SCSetProtocolID(SConnection *pCon, int proID); void SCSetGrab(SConnection *pCon, int iGrab); - +void SCSetEnd(SConnection *pCon, int val); +void SCSetTelnet(SConnection *pCon, int val); /* **************************** Invocation ******************************** */ int SCInvoke(SConnection * self, SicsInterp * pInter, char *pCommand); diff --git a/nread.c b/nread.c index 1c9d9a9d..3b752dcf 100644 --- a/nread.c +++ b/nread.c @@ -194,439 +194,6 @@ int NetReadRemove(pNetRead self, mkChannel * pSock) } return 0; } - -/*-------------------------------------------------------------------------*/ -static int NetReadAccept(pNetRead self, mkChannel * pSock) -{ - mkChannel *pNew = NULL; - char pBuffer[1064]; - int iRet; - SConnection *pRes = NULL; - char *pUser = NULL, *pPasswd = NULL; - time_t target; - - if (!VerifyChannel(pSock)) { - return 0; - } - - /* check for new connection */ - pNew = NETAccept(pSock, 0); - if (pNew) { - /* create connection object */ - /* TODO - pRes = SCreateConnection(self->pMain->pSics,pNew,3); - */ - if (!pRes) { - Log(ERROR,"sys","%s","Failure to allocate new Connection"); - NETClosePort(pNew); - free(pNew); - return 0; - } else { - /* register the connection and create a task for it here */ - NetReadRegister(self, pNew, command, pRes); - TaskRegisterN(self->pMain->pTasker, "NetReadAccept", - SCTaskFunction, - SCSignalFunction, SCDeleteConnection, pRes, TASK_PRIO_LOW); - SCSendOK(pRes); - return 1; - } - } else { - return 0; - } -} - -/*--------------------------------------------------------------------------*/ -#define COLLECT 0 -#define SKIPTERM 1 -/*------------------------------------------------------------------------*/ -static int NetReadRead(pNetRead self, pNetItem pItem) -{ - char *pPtr, *pEnd, *pBufEnd; - char pBuffer[1024], pMuell[20]; - char pBueffel[80]; - int i, iInt, iRet, iStat, state; - - /* read first */ - memset(pBuffer, 0, 1024); - iRet = NETRead(pItem->pCon->pSock, pBuffer, 1022, 0); - if (iRet < 0) { /* EOF */ - pItem->pCon->iEnd = 1; - NetReadRemove(self, pItem->pCon->pSock); - return 0; - } else if (iRet == 0) { /* should not happen */ - return 1; - } - /* iRet is now the number of bytes read. Now we check for command - interrupts */ - pPtr = strstr(pBuffer, "INT1712"); - if (pPtr) { - sscanf(pPtr, "%s %d", pMuell, &iInt); - if (SCMatchRights(pItem->pCon, usUser)) { - TaskSignal(self->pMain->pTasker, SICSINT, &iInt); - Log(ERROR,"com","sock%03.3d:INTERRUPT", pItem->pCon->pSock->sockid); - if (iInt == eEndServer) { - TaskStop(self->pMain->pTasker); - } - } else { - SCWrite(pItem->pCon, - "ERROR: insufficient privilege to invoke Interrupt", eError); - } - return 0; - } - - /* split into command lines - and put into fifo - */ - pBufEnd = pBuffer + iRet; - pPtr = pBuffer; - pEnd = pBuffer; - state = COLLECT; - while (pEnd < pBufEnd) { - switch (state) { - case COLLECT: - if ((*pEnd != '\r') && (*pEnd != '\n')) { - pEnd++; - } else { - /* there is a string between pPtr and pEnd */ - *pEnd = '\0'; - /* do we have something in hold ? */ - if (strlen(pItem->pHold) > 0) { - strlcat(pItem->pHold, pPtr, 511); - /* DFC locking for protocol zero only */ - if (pItem->pCon->iProtocolID == PROTSICS && - CostaLocked(pItem->pCon->pStack)) - iStat = 0; - else - iStat = CostaTop(pItem->pCon->pStack, pItem->pHold); - if (!iStat) { - SCWrite(pItem->pCon, "ERROR: Busy", eError); - } - pItem->pHold[0] = '\0'; - } else { - /* no, normal command */ - /* DFC locking for protocol zero only */ - if (pItem->pCon->iProtocolID == PROTSICS && - CostaLocked(pItem->pCon->pStack)) - iStat = 0; - else - iStat = CostaTop(pItem->pCon->pStack, pPtr); - if (!iStat) { - SCWrite(pItem->pCon, "ERROR: Busy", eError); - } - } - pPtr = pEnd + 1; - pEnd = pPtr; - state = SKIPTERM; - } - break; - case SKIPTERM: - if ((*pEnd != '\r') && (*pEnd != '\n')) { - state = COLLECT; - pPtr = pEnd; - } else { - pEnd++; - pPtr = pEnd; - } - break; - } - } - /* when we are here we may still have an incomplete command pending */ - if (pEnd != pPtr && strlen(pPtr) > 0) { - strlcpy(pItem->pHold, pPtr, 511); - } - return 1; -} - -/*-------------------------- telnet protocoll code -------------------------*/ -static int TelnetAccept(pNetRead self, mkChannel * pSock) -{ - mkChannel *pNew = NULL; - char pBuffer[1064]; - int iRet; - SConnection *pRes = NULL; - pTelTask pTel = NULL; - - if (!VerifyChannel(pSock)) { - return 0; - } - - /* check for new connection */ - pNew = NETAccept(pSock, 0); - if (pNew) { - /* create connection object */ - /* TODO - pRes = SCreateConnection(self->pMain->pSics,pNew,usSpy); - */ - if (!pRes) { - Log(ERROR,"sys","%s","Failure to allocate new Connection"); - NETClosePort(pNew); - free(pNew); - return 0; - } else { - /* Create a task object for the telnet connection */ - pTel = CreateTelnet(pRes); - if (!pTel) { - Log(ERROR,"sys","%s","Failure to allocate new Telnet Task Object"); - SCDeleteConnection(pRes); - return 0; - } - /* register connection and task */ - pRes->iTelnet = 1; - NetReadRegister(self, pNew, tcommand, pRes); - TaskRegisterN(self->pMain->pTasker," TelnetAccept", - TelnetTask, TelnetSignal, DeleteTelnet, pTel, TASK_PRIO_LOW); - return 1; - } - } else { - return 0; - } -} - -/*------------------------------------------------------------------------ - Telnet is fully described in RFC-854. This implementation is very simple. - It just supports the NVT and no options. Implementation is via a state - machine with the state tStatus in the pItem structure. This is necessary - as single characters may be sent by telnet clients. --------------------------------------------------------------------------*/ -/* Telnet codes */ -#define SE 240 -#define NOP 241 -#define DM 242 /* data mark */ -#define BRK 243 -#define IP 244 -#define AO 245 -#define AYT 246 -#define EC 247 -#define EL 248 -#define GA 249 -#define SB 250 -#define WILL 251 -#define WONT 252 -#define DO 253 -#define DONT 254 -#define IAC 255 -#define EOR 239 -/*-----------------------------------------------------------------------*/ -static int TelnetReply(pNetItem pItem, char code, char cChar) -{ - char pReply[3]; - - pReply[0] = IAC; - pReply[1] = code; - pReply[2] = cChar; - - NETWrite(pItem->pCon->pSock, pReply, 3); - return 1; -} - -/*------------------------------------------------------------------------*/ -static int TelnetRead(pNetRead self, pNetItem pItem) -{ - char pBuffer[1024], pMuell[20], pError[256]; - int i, iStat, iInt, iRet; - int cChar; - char *pPtr = NULL; - SConnection *pOwner = NULL; - - /* read first */ - memset(pBuffer, 0, 1023); - iRet = NETRead(pItem->pCon->pSock, pBuffer, 1022, 0); - if (iRet < 0) { /* EOF */ - pItem->pCon->iEnd = 1; - NetReadRemove(self, pItem->pCon->pSock); - return 0; - } else if (iRet == 0) { /* should not happen */ - return 1; - } - - /* iRet is now the number of bytes read. Now we check for command - interrupts */ - pPtr = strstr(pBuffer, "INT1712"); - if (pPtr) { - sscanf(pPtr, "%s %d", pMuell, &iInt); - if (SCMatchRights(pItem->pCon, usUser)) { - /* owners may kill own tasks, otherwise manager - privilege is required. - */ - pOwner = GetExeOwner(pServ->pExecutor); - if (pOwner) { - if (pOwner != pItem->pCon) { - if (!SCMatchRights(pItem->pCon, usMugger)) { - SCWrite(pItem->pCon, - "ERROR: Insufficient privilege to stop other people's experiments", - eError); - return 1; - } - } - } - TaskSignal(self->pMain->pTasker, SICSINT, &iInt); - Log(ERROR,"com","%s:interrupt: %d", ConID(pItem->pCon),iInt); - if (iInt == eEndServer) { - TaskStop(self->pMain->pTasker); - } - } else { - SCWrite(pItem->pCon, - "ERROR: insufficient privilege to invoke Interrupt", eError); - } - return 1; - } - - /* do telnet analysis of the data buffer */ - for (i = 0; i < iRet; i++) { - cChar = (int) pBuffer[i]; -#ifdef TELNETDEBUG - if ((cChar > 48) && (cChar < 128)) { - printf("char: %c\n", cChar); - } else { - printf("Control: %d\n", cChar); - } -#endif - /* Telnet status switching */ - switch (pItem->tStatus) { - case tData: - switch (cChar) { - case IAC: - pItem->tStatus = tIAC; - break; - case '\r': - case '\n': - /* DFC locking for protocol zero only */ - if (pItem->pCon->iProtocolID == PROTSICS && - CostaLocked(pItem->pCon->pStack)) - iStat = 0; - else - iStat = CostaTop(pItem->pCon->pStack, pItem->pHold); - /* printf("%s\n",pItem->pHold); */ - if (!iStat) { - SCWrite(pItem->pCon, "ERROR: Busy", eError); - } - memset(pItem->pHold, 0, 511); - pItem->iEOD = 0; - pItem->tStatus = tCR; - break; - case (char) 8: /* backspace */ - pItem->iEOD--; - if (pItem->iEOD < 0) { - pItem->iEOD = 0; - } - break; - case (char) 0: /* ignore 0 character sent as end of text */ - break; - default: - pItem->pHold[pItem->iEOD] = cChar; - pItem->iEOD++; - break; - - } /* end of tData case */ - break; - case tCR: /* ignore the second character after a newline. - Telnet gives you two characters for newline - */ - pItem->tStatus = tData; - break; - case tIAC: - switch (cChar) { - case IAC: - pItem->tStatus = tData; - break; - case WILL: - pItem->tStatus = tWill; - break; - case WONT: - pItem->tStatus = tWont; - break; - case DONT: - pItem->tStatus = tDont; - break; - case DO: - pItem->tStatus = tDo; - break; - case EOR: - pItem->tStatus = tData; - break; - case SB: - pItem->tStatus = tSB; - break; - case EC: - pItem->iEOD--; - if (pItem->iEOD < 0) { - pItem->iEOD = 0; - } - pItem->tStatus = tData; - break; - case EL: - memset(pItem->pHold, 0, 511); - pItem->iEOD = 0; - pItem->tStatus = tData; - break; - case IP: - SCSetInterrupt(pItem->pCon, eAbortBatch); - pItem->tStatus = tData; - break; - default: - pItem->tStatus = tData; - break; - } /* end of tIAC */ - break; - case tWill: /* we do not do options! */ - TelnetReply(pItem, DONT, cChar); - pItem->tStatus = tData; - break; - case tWont: /* we do not do options! A Wont is sent by the client - if it cannot do a option we requested it to have. As - we do not try to force options, this should not happen - */ - pItem->tStatus = tData; - break; - case tDo: /* we do not do options! */ - TelnetReply(pItem, WONT, cChar); - pItem->tStatus = tData; - break; - case tDont: /* we do not do options! A Dont is sent by the client - if it cannot do a option we requested it to have. As - we do not try to force options, this should not happen - */ - pItem->tStatus = tData; - break; - case tSB: /* as we do not have options, we cannot have suboption - negotaitions. Something is seriously wrong when - we are here. It is a protocoll error. However, we - ignore it silently. tSB marks the start of the - subnegotiation. The current character must be the - option code we are dealing with. - */ - pItem->tStatus = tSE; - break; - case tSE: - /* now we are in the suboption parameter. Normally data - should be copied to a suboption string buffer here - until SE. - */ - switch (cChar) { - case IAC: - break; - case SE: - pItem->tStatus = tData; - /* suboption interpretation would go here */ - break; - default: - /* copy data to suboption buffer */ - break; - } - break; - - default: - /* There is something wrong here! */ - snprintf(pError,sizeof(pError)-1, "ERROR: bad telnet code %d", cChar); - Log(ERROR,"sys","%s",pError); - pItem->tStatus = tData; - break; - - } - } - return 1; -} - /*---------------------------------------------------------------------------*/ static int NetReadUDP(pNetRead self, pNetItem pItem) { @@ -708,13 +275,6 @@ int NetReaderTask(void *pData) GetCharArray(self->conList)); } - /* - * This costs a surprising amount of CPU-time, in a test 10%! - * This is why it has been commented away - snprintf(num, sizeof num, "%d", conCount); - IFSetOption(pSICSOptions, "ConnectionCount", num); - IFSetOption(pSICSOptions, "ConMask", GetCharArray(self->conList)); -*/ /* the select itself */ tmo.tv_usec = self->iReadTimeout; @@ -731,29 +291,6 @@ int NetReaderTask(void *pData) LLDnodeDataTo(self->iList, &NItem); if (FD_ISSET(NItem.pSock->sockid, &lMask)) { /* data */ switch (NItem.eType) { - /* lists have been changed after accept, return */ - case naccept: - NetReadAccept(self, NItem.pSock); - return 1; - break; - case taccept: - TelnetAccept(self, NItem.pSock); - return 1; - break; - case command: - iStatus = NetReadRead(self, &NItem); - if (iStatus == 0) { /* there was an eof */ - /* do not continue, list is messy */ - return 1; - } - break; - case tcommand: - iStatus = TelnetRead(self, &NItem); - if (iStatus == 0) { /* there was an eof */ - /* do not continue, list is messy */ - return 1; - } - break; case udp: NetReadUDP(self, &NItem); break; @@ -1048,6 +585,10 @@ static int testAndInvokeInterrupt(pCommandCBData self, int handle) } return 0; } +/*----------------------------------------------------------------------------------*/ +#define COLLECT 0 +#define SKIPTERM 1 + /*----------------------------------------------------------------------------------*/ static int CommandDataCB(int handle, void *userData) @@ -1114,7 +655,7 @@ static int CommandAcceptCB(int handle, void *userData) } usData->pCon = pCon; usData->state = COLLECT; - snprintf(buffer,sizeof(buffer),"con%ld", pCon->ident); + snprintf(buffer,sizeof(buffer),"con%ld", SCGetIdent(pCon)); TaskRegisterN(pServ->pTasker, buffer, SCTaskFunction, @@ -1123,6 +664,30 @@ static int CommandAcceptCB(int handle, void *userData) SCSendOK(pCon); return 1; } +/*------------------------------------------------------------------------ + Telnet is fully described in RFC-854. This implementation is very simple. + It just supports the NVT and no options. Implementation is via a state + machine with the state tStatus in the pItem structure. This is necessary + as single characters may be sent by telnet clients. +-------------------------------------------------------------------------*/ +/* Telnet codes */ +#define SE 240 +#define NOP 241 +#define DM 242 /* data mark */ +#define BRK 243 +#define IP 244 +#define AO 245 +#define AYT 246 +#define EC 247 +#define EL 248 +#define GA 249 +#define SB 250 +#define WILL 251 +#define WONT 252 +#define DO 253 +#define DONT 254 +#define IAC 255 +#define EOR 239 /*-----------------------------------------------------------------------*/ static int ANETTelnetReply(int sockHandle, char code, char cChar) @@ -1329,8 +894,8 @@ static int TelnetAcceptCB(int handle, void *userData) return 0; } /* register connection and task */ - pCon->iTelnet = 1; - snprintf(buffer,sizeof(buffer),"con%ld", pCon->ident); + SCSetTelnet(pCon,1); + snprintf(buffer,sizeof(buffer),"con%ld", SCGetIdent(pCon)); TaskRegisterN(pServ->pTasker, buffer, TelnetTask, TelnetSignal, DeleteTelnet, pTel, TASK_PRIO_LOW); diff --git a/telnet.c b/telnet.c index 5204d8fc..ceb8723e 100644 --- a/telnet.c +++ b/telnet.c @@ -13,6 +13,8 @@ #include "passwd.h" #include "telnet.h" #include "fortify.h" +#include "asynnet.h" +#include "conman.h" #define LOGINWAIT 300 /* 300 == 5 minutes to wait for valid username password */ /*-------------------------------------------------------------------------*/ @@ -96,7 +98,7 @@ static void SendGA(SConnection * pCon) pReply[0] = (char) 255; pReply[1] = (char) 249; - NETWrite(pCon->pSock, pReply, 2); + ANETwrite(SCGetSockHandle(pCon), pReply, 2); } /*--------------------------------------------------------------------------*/ @@ -113,7 +115,7 @@ int TelnetTask(void *pData) self = (pTelTask) pData; assert(self); - if (self->pCon->iEnd) { + if (SCGetEnd(self->pCon)) { if (SCActive(self->pCon)) { return 1; } else { @@ -122,21 +124,20 @@ int TelnetTask(void *pData) } /* pop and execute */ - iRet = CostaPop(self->pCon->pStack, &pPtr); + iRet = SCCostaTop(self->pCon,pPtr); if (iRet) { if (pPtr) { if (self->iLogin) { /* handle normal command */ /* check for logoff */ if (strstr(pPtr, "logoff") != NULL) { - ANETclose(self->pCon->sockHandle); + SCClose(self->pCon); free(pPtr); - self->pCon->iEnd = 1; return 0; } /* invoke command */ - CostaLock(self->pCon->pStack); + SCCostaLock(self->pCon); SCInvoke(self->pCon, pServ->pSics, pPtr); - CostaUnlock(self->pCon->pStack); + SCCostaUnLock(self->pCon); SendGA(self->pCon); free(pPtr); } else { /* handle login messages */ @@ -149,8 +150,7 @@ int TelnetTask(void *pData) if (time(&shit) > self->tStart + LOGINWAIT) { SCWrite(self->pCon, "I cannot stand your login attempts anymore!", eError); - ANETclose(self->pCon->sockHandle); - self->pCon->iEnd = 1; + SCClose(self->pCon); free(pPtr); return 0; } @@ -172,7 +172,7 @@ int TelnetTask(void *pData) return 1; } else { snprintf(pBuffer,sizeof(pBuffer)-1, "Accepted telnet connection on handle %d", - self->pCon->sockHandle); + SCGetSockHandle(self->pCon)); Log(INFO,"com","%s",pBuffer); SendWelcome(self->pCon); SCSetRights(self->pCon, iRet); @@ -187,14 +187,14 @@ int TelnetTask(void *pData) } /* check for no commands but timeout on telnet */ if (!self->iLogin && (time(&shit) > self->tStart + LOGINWAIT)) { - self->pCon->iEnd = 1; - ANETclose(self->pCon->sockHandle); + SCSetEnd(self->pCon,1); + SCClose(self->pCon); return 0; } /* check for end */ - if (self->pCon->iEnd) { + if (SCGetEnd(self->pCon)) { if (SCActive(self->pCon)) { return 1; } else { @@ -219,7 +219,7 @@ void TelnetSignal(void *pData, int iSignal, void *pSigData) iInt = (int *) pSigData; SCSetInterrupt(self->pCon, *iInt); if (*iInt == eEndServer) { - self->pCon->iEnd = 1; + SCSetEnd(self->pCon,1); } } else if (iSignal == SICSBROADCAST) { pPtr = (char *) pSigData; @@ -227,9 +227,9 @@ void TelnetSignal(void *pData, int iSignal, void *pSigData) SCWrite(self->pCon, pPtr, eWarning); } } else if (iSignal == TOKENRELEASE) { - self->pCon->iGrab = 0; + SCSetGrab(self->pCon,0); } else if (iSignal == TOKENGRAB) { - self->pCon->iGrab = 1; + SCSetGrab(self->pCon,1); } }