/*-------------------------------------------------------------------------- Connection management for SICS. This is one the core files for SICS. Does a lot. See the descriptions with individual functions below. Mark Koennecke, October 1996 SMInvoke added. Mark Koennecke, April 1997 Seriously revised and extended for new structure with Tasker: Mark Koennecke, September 1997 Support for writing telnet compatible strings ins SCWrite added. Mark Koennecke, January 1998 SCWriteBinary added. Mark Koennecke, April 1998 Revamped login to non telnet connection. Added compressed writing method. Mark Koennecke, October 2000 Added simulation mode Mark Koennecke, March 2003 Refactored a bit, removed SCWriteBinary (never used anywhere), added appending outcode to text, Mark Koennecke, July 2004 Made use of unused connections secure (connections are not freed, but reused on new connections). Introduced new type SCStore and functions SCSave, SCLoad. Introduced SCPrintf to avoid many of these pBueffel. Markus Zolliker, Sept 2004. Cleaned up conman data structure. Removed left over and unused fields. Mark Koennecke, December 2004 Aded buffering support, Mark Koennecke, July 2006 Copyright: see copyright.h substantially revised for asynchronous I/O Mark Koennecke, January 2009 Removed old cruft including SCStore. Added accessor functions to make the connection object more private Mark Koennecke, October 2016 -----------------------------------------------------------------------------*/ #include "fortify.h" #include #include #include #include #include #include #include #include #include #include #include "lld.h" #include "sics.h" #include "passwd.h" #include "splitter.h" #include "macro.h" #include "status.h" #include "interrupt.h" #include "ifile.h" #include "token.h" #include "uubuffer.h" #include "stptok.h" #include "statusfile.h" #include "sicshipadaba.h" #include "protocol.h" #include "sicsvar.h" #include /* Greetings from protocol.c for SCLogWrite... */ extern struct json_object *mkJSON_Object(SConnection * pCon, char *pBuffer, int iOut); /* from loglisten.c */ void LogListenRegister(SConnection * pCon); /* #define UUDEB 1 define UUDEB , for buffer writing for checking encoding */ extern pServer pServ; #include "outcode.h" /* text for OutCode */ int KillCapture(SConnection * pCon); int LogCapture(SConnection * pCon, SicsInterp * pInter, void *pData, int argc, char *argv[]); int LogOutput(SConnection * pCon, SicsInterp * pInter, void *pData, int argc, char *argv[]); /*------ Max Size of Command Stack */ #define MAXSTACK 1024 /*---------- Magic ID Header */ #define CONMAGIC 26051958 /*------------------------------------------------------------------------- a structure for holding callback info */ typedef struct { long lID; pICallBack pInterface; } Item; /*------------- a number for generating automatic names --------------------*/ static int iName = 0; static long lastIdent = 0; /* * This will return the value of a SICS int variable called "sicsdebug" * If sicsdebug is not defined it will return 1 * TODO Maybe define debugging levels. * * return 0=debug off, 1=debug on or sicsdebug not defined. */ int sicsdebug() { pSicsVariable debug; debug = FindVariable(pServ->pSics, "sicsdebug"); if (debug) { return debug->iVal; } else { return 1; } } /*===========================================================================*/ static char *ConName(long ident) { static char name[32]; snprintf(name, sizeof(name), "CON%ld", ident); return name; } /*--------------------------------------------------------------------------*/ char *ConID(SConnection *pCon) { static char id[132]; char host[80]; if(ANETvalidHandle(pCon->sockHandle)){ ANETinfo(pCon->sockHandle, host, sizeof(host)); snprintf(id,sizeof(id),"%s:sock%3.3d", host, pCon->sockHandle); } else { snprintf(id,sizeof(id),"disconnected:con%ld", pCon->ident); } return id; } /*--------------------------------------------------------------------------*/ static void FreeConnection(SConnection * pCon) { free(pCon); } /*--------------------------------------------------------------------------*/ static SConnection *SCMakeConnection() { SConnection *pRes = NULL; pRes = (SConnection *) malloc(sizeof(SConnection)); if (!pRes) { /* This is a serious, very serious error! */ Log(ERROR,"sys","%s","No memory to allocate connection!!"); return NULL; } memset(pRes, 0, sizeof(SConnection)); return pRes; } /*--------------------------------------------------------------------------*/ static SConnection *CreateConnection(SicsInterp * pSics) { int i; SConnection *pRes = NULL; char pBueffel[253]; char pHost[132]; pRes = SCMakeConnection(); do { /* loop until an unused ident is found. This test needed only for the case there some object has already the name con. In a live cycle of SICS, no connection ever can get an earlier used name */ if (lastIdent == LONG_MAX) { /* This is a serious, very serious error! */ Log(FATAL,"sys""%s","Run out of connection identifiers!!"); return NULL; } lastIdent++; } while (FindCommand(pSics, ConName(lastIdent))); pRes->ident = lastIdent; /* a descriptor */ pRes->pDes = CreateDescriptor("Connection"); if (!pRes->pDes) { /* This is a serious, very serious error! */ Log(ERROR,"sys","%s","No memory to allocate connection!!"); FreeConnection(pRes); return NULL; } /* the callback registry */ pRes->iList = LLDcreate(sizeof(Item)); /* the command stack */ pRes->pStack = CreateCommandStack(); if ((pRes->iList < 0) || (!pRes->pStack)) { /* This is a serious, very serious error! */ Log(ERROR,"sys","%s","No memory to allocate connection!!"); DeleteDescriptor(pRes->pDes); FreeConnection(pRes); return NULL; } pRes->iOutput = eInError; /* gets everything except internal messages */ pRes->inUse = 0; pRes->iMacro = 0; pRes->iTelnet = 0; pRes->eInterrupt = eContinue; pRes->lMagic = CONMAGIC; pRes->iLogin = 0; pRes->listening = 0; pRes->conStart = time(NULL); pRes->write = SCNormalWrite; pRes->runLevel = RUNDRIVE; pRes->remote = 0; /* initialise context variables */ pRes->iCmdCtr = 0; pRes->conEventType = -1; pRes->conStatus = -1; pRes->contextStack = LLDcreate(sizeof(commandContext)); /* install command */ AddCommand(pSics, ConName(pRes->ident), ConSicsAction, NULL, pRes); return pRes; } /*--------------------------------------------------------------------------*/ SConnection *SCreateConnection(SicsInterp * pSics, int sockHandle, int iUser) { SConnection *pRes = NULL; char pBueffel[253]; char pHost[132]; pRes = CreateConnection(pSics); SetCommandStackMaxSize(pRes->pStack, MAXSTACK); pRes->sockHandle = sockHandle; pRes->iUserRights = iUser; pRes->iGrab = TokenGrabActive(); return pRes; } /*--------------------------------------------------------------------------*/ SConnection *SCCreateDummyConnection(SicsInterp * pSics) { SConnection *pRes = NULL; pRes = CreateConnection(pSics); if(pRes == NULL){ return pServ->dummyCon; } pRes->sockHandle = -1; pRes->iUserRights = usInternal; pRes->iGrab = 0; /* Log(INFO,"SYS","%s","Accepted dummy connection "); */ return pRes; } /*--------------------------------------------------------------------------*/ int VerifyConnection(SConnection * self) { static SConnection *previous = NULL; if (!self) { Log(ERROR,"sys","%s","MAGICERROR: Invalid call to NULL connection"); return 0; } if (self->lMagic != CONMAGIC) { if (self != previous) { previous = self; Log(ERROR,"sys","%s","MAGICERROR: corrupted connection object"); } return 0; } return 1; } /*----------------------------------------------------------------------------*/ void SCSetOutputClass(SConnection * self, int iClass) { if (!VerifyConnection(self)) { return; } self->iOutput = iClass; } /*---------------------------------------------------------------------------*/ int SCinMacro(SConnection * self) { if (!VerifyConnection(self)) { return 0; } if (self->iMacro) { return 1; } else { return 0; } } /*---------------------------------------------------------------------------*/ int SCsetMacro(SConnection * self, int iMode) { if (!VerifyConnection(self)) { return 0; } assert((iMode == 0) || (iMode == 1)); self->iMacro = iMode; /* SCPrintf(self,eError, "SCsetMacro = %lx, %d\n", (long int)self, iMode); */ return 1; } /*--------------------------------------------------------------------------*/ void SCDeleteMasterFields(SConnection * pVictim) { int iRet; Item sItem; pHdb root = NULL; char pBueffel[512]; if (pVictim->pDes == NULL) { return; } if (SCActive(pVictim)) { SCnoSock(pVictim); ANETclose(pVictim->sockHandle); Log(ERROR,"sys","%s","Erraneous deletion of used Connection stopped"); pVictim->sockHandle = -1; return; } /* remove the connection from the server log if it has captured something */ KillCapture(pVictim); /* * remove any callbacks which might still be active in the Hipadaba */ root = GetHipadabaRoot(); if (root != NULL) { RemoveConnectionCallbacks(root, pVictim); } /* If we have a grab, release it ! */ if (!pVictim->iGrab) { if (pServ->pTasker) { TaskSignal(pServ->pTasker, TOKENRELEASE, NULL); TokenRelease(); } } /* log the kill */ if (pVictim->sockHandle >= 0 && pVictim->iLogin == 1 && pVictim->iUserRights < 3) { sprintf(pBueffel, "Deleting connection %d", pVictim->sockHandle); Log(DEBUG,"sys","%s", pBueffel); } /* close all open files and sockets */ if (pVictim->sockHandle > 0) { ANETwrite(pVictim->sockHandle, "SICSCLOSE", sizeof("SICSCLOSE")); ANETprocess(); ANETclose(pVictim->sockHandle); } RemoveCommand(pServ->pSics, ConName(pVictim->ident)); /* remove all callbacks on this connection */ iRet = LLDnodePtr2First(pVictim->iList); while (iRet != 0) { LLDnodeDataTo(pVictim->iList, &sItem); RemoveCallback(sItem.pInterface, sItem.lID); iRet = LLDnodePtr2Next(pVictim->iList); } LLDdelete(pVictim->iList); LLDdelete(pVictim->contextStack); DeleteDescriptor(pVictim->pDes); } /*---------------------------------------------------------------------------*/ void SCDeleteConnection(void *pData) { int i, iRet; char pBueffel[132]; SConnection *pVictim = NULL; pVictim = (SConnection *) pData; if (!VerifyConnection(pVictim)) { return; } SCDeleteMasterFields(pVictim); /* remove command stack */ if (pVictim->pStack != NULL) { DeleteCommandStack(pVictim->pStack); } /* remove possible buffers */ if (pVictim->data != NULL && pVictim->dataOwner == 1) { DeleteDynString(pVictim->data); } pVictim->lMagic = 0; /* make a write to a freed connection harmless */ /* finally free pVictim */ FreeConnection(pVictim); } /*--------------------------------------------------------------------------*/ SConnection *SCCopyConnection(SConnection * pCon) { SConnection *result = NULL; result = SCMakeConnection(); if (result == NULL) { return NULL; } result->sockHandle = pCon->sockHandle; result->lMagic = pCon->lMagic; result->iUserRights = pCon->iUserRights; result->ident = pCon->ident; result->iMacro = pCon->iMacro; result->iTelnet = pCon->iTelnet; result->iOutput = pCon->iOutput; if (pCon->oldWriteFunc != NULL) result->write = pCon->oldWriteFunc; else result->write = pCon->write; result->listening = pCon->listening; result->eInterrupt = pCon->eInterrupt; result->inUse = pCon->inUse; result->sicsError = pCon->sicsError; result->iCmdCtr = pCon->iCmdCtr; result->conEventType = pCon->conEventType; result->conStatus = pCon->conStatus; result->iProtocolID = pCon->iProtocolID; result->transID = pCon->transID; strcpy(result->deviceID, pCon->deviceID); result->conStart = pCon->conStart; result->contextStack = -1; result->iList = -1; result->runLevel = pCon->runLevel; result->data = pCon->data; result->remote = pCon->remote; return result; } /*---------------------------------------------------------------------------*/ SConnection *SCfindMaster(SConnection * pCon) { SConnection *result = NULL; result = (SConnection *) FindCommandData(pServ->pSics, ConName(pCon->ident), "Connection"); if (result == NULL) { printf("VERY, Very, very serious programming error!\n"); printf("I continue but things may be wrong! Please debug ASAP!\n"); if (pServ->dummyCon == NULL) { pServ->dummyCon = SCCreateDummyConnection(pServ->pSics); } result = pServ->dummyCon; } return result; } /*---------------------------------------------------------------------------*/ int SCisConnected(SConnection * pCon) { if (!VerifyConnection(pCon)) { return 0; } return ANETvalidHandle(pCon->sockHandle); } /*---------------------------------------------------------------------------*/ static int HasNL(char *buffer) { int i; for (i = strlen(buffer); i > 0; i--) { if (isprint(buffer[i])) { break; } if (buffer[i] == '\n') { return 1; } } return 0; } /*------------------------------------------------------------------------- TelnetWrite makes sure, that all lines are properly terminated with a as required by the telnet protocoll. There may be a problem here at long messages. 7.5.1998 MK --------------------------------------------------------------------------*/ #define TXT 0 #define LF 1 /*-----------------------------------------------------------*/ int TelnetWriteANET(int sockHandle, char *pBuffer) { char *pStart = NULL, *pPtr; int iCount, iState; int iRet = 1; pStart = pBuffer; pPtr = pStart; iState = TXT; iCount = 0; while (*pPtr != '\0') { switch (iState) { case TXT: if ((*pPtr == '\r') || (*pPtr == '\n')) { iState = LF; iRet = ANETwrite(sockHandle, pStart, iCount); iRet = ANETwrite(sockHandle, "\r\n", 2); iCount = 0; } else { iCount++; } break; case LF: if ((*pPtr != '\r') && (*pPtr != '\n')) { pStart = pPtr; iCount = 1; iState = TXT; } else { /* do nothing */ } break; } pPtr++; } if (iCount > 0) { iRet = ANETwrite(sockHandle, pStart, iCount); iRet = ANETwrite(sockHandle, "\r\n", 2); } return iRet; } /*------------------------------------------------------------------------*/ static int mustWrite(int iOut) { switch(iOut) { case eLog: case eLogError: return 1; default: return 0; } } /*-------------------------------------------------------------------------*/ int SCWrite(SConnection * self, char *pBuffer, int iOut) { if (!VerifyConnection(self)) { return 0; } /* Do not die if no data */ if (pBuffer == NULL) { return 0; } return self->write(self, pBuffer, iOut); } /*-----------------------------------------------------------------------*/ int SCWriteInContext(SConnection * pCon, char *pBuffer, int out, commandContext cc) { int status; int transID; char oldDevice[256]; transID = pCon->transID; strcpy(oldDevice, pCon->deviceID); pCon->transID = cc.transID; strlcpy(pCon->deviceID, cc.deviceID, SCDEVIDLEN); status = SCWrite(pCon, pBuffer, out); pCon->transID = transID; strlcpy(pCon->deviceID, oldDevice, SCDEVIDLEN); return status; } /*-------------------------------------------------------------------------*/ int SCPrintf(SConnection * self, int iOut, char *fmt, ...) { va_list ap; char buf[256]; char *dyn; unsigned int l; int res; va_start(ap, fmt); l = vsnprintf(buf, sizeof buf, fmt, ap); va_end(ap); if (l >= sizeof buf) { /* we have probably a C99 conforming snprintf and need a larger buffer */ dyn = malloc(l + 1); if (dyn != NULL) { va_start(ap, fmt); vsnprintf(dyn, l + 1, fmt, ap); va_end(ap); res = SCWrite(self, dyn, iOut); free(dyn); return res; } } return SCWrite(self, buf, iOut); } /*-------------------------------------------------------------------------*/ int SCPf(writeFunc func, SConnection * self, int iOut, char *fmt, ...) { va_list ap; char buf[256]; char *dyn; unsigned int l; int res; va_start(ap, fmt); l = vsnprintf(buf, sizeof buf, fmt, ap); va_end(ap); if (l >= sizeof buf) { /* we have probably a C99 conforming snprintf and need a larger buffer */ dyn = malloc(l + 1); if (dyn != NULL) { va_start(ap, fmt); vsnprintf(dyn, l + 1, fmt, ap); va_end(ap); res = func(self, dyn, iOut); free(dyn); return res; } } return func(self, buf, iOut); } /*-------------------------------------------------------------------------*/ writeFunc SCGetWriteFunc(SConnection * self) { if (!VerifyConnection(self)) { return 0; } return self->write; } /*-------------------------------------------------------------------------*/ void SCSetWriteFunc(SConnection * self, writeFunc x) { if (!VerifyConnection(self)) { return; } self->write = x; } /*------------------------------------------------------------------------*/ static int doSockWrite(SConnection * self, char *buffer) { int iRet = 1; if (self->sockHandle >= 0) { if (self->iTelnet) { iRet = TelnetWriteANET(self->sockHandle, buffer); } else { iRet = ANETwrite(self->sockHandle, buffer, strlen(buffer)); if (!HasNL(buffer)) { iRet = ANETwrite(self->sockHandle, "\n", strlen("\n")); } } if (!iRet) { SCnoSock(self); if (!self->listening && self->iLogin == 1 && self->iUserRights < 3) { Log(ERROR,"sys","%s", "Connection broken on send"); } } } else { if (HasNL(buffer)) { fputs(buffer, stdout); } else { puts(buffer); } } return iRet; } /*--------------------------------------------------------------------------*/ static void testAndStoreInTcl(SConnection * pCon, char *buffer, int iOut) { if (SCinMacro(pCon)) { if (iOut == eValue || iOut == eError) { InterpWrite(pServ->pSics, buffer); } } } /*-------------------------------------------------------------------------*/ static int testAndWriteSocket(SConnection * pCon, char *buffer, int iOut) { switch (iOut) { case eStatus: case eStart: case eFinish: case eEvent: case eHdbValue: case eHdbEvent: case eLog: case eLogError: return doSockWrite(pCon, buffer); break; case eValue: case eError: case eWarning: if (!SCinMacro(pCon) && iOut >= pCon->iOutput) { return doSockWrite(pCon, buffer); } else { return 0; } break; } printf("Unrecognized ouput code %d in testAndWriteSocket: FIX!!!\n", iOut); return 0; } /*--------------------------------------------------------------------------*/ static int isOK(const char *buffer) { if ((buffer[0] == 'O' && buffer[1] == 'K') && (buffer[2] == '\0' || buffer[2] == '\r' || buffer[2] == '\n')) return 1; return 0; } /*--------------------------------------------------------------------------*/ static void testAndWriteLog(SConnection * self, char *buffer, int iOut) { unsigned int severity; /* first those which allways go into the log */ if(SCGetRights(self) > usUser) { severity = DEBUG; } else { severity = INFO; } switch(iOut){ case eInternal: Log(ERROR,"sys","%s",buffer); break; case eCommand: if(!SCinMacro(self)){ Log(DEBUG,"sys","%s",buffer); } break; case eHWError: case eInError: Log(ERROR,"dev","%s",buffer); break; case eStatus: Log(DEBUG,"io","%s",buffer); break; case eEvent: if(strstr(buffer,"ERROR") != NULL){ Log(ERROR,"notify",buffer); }else if(strstr(buffer,"WARNING") != NULL) { Log(WARN,"notify",buffer); } else { Log(DEBUG,"notify",buffer); } break; case eHdbEvent: case eHdbValue: Log(INFO,"notify","%s",buffer); break; case eLog: Log(severity,"com","sock%03.3d:%s",self->sockHandle,buffer); break; case eLogError: Log(ERROR,"com","sock%03.3d:%s",self->sockHandle,buffer); break; case eError: if(!SCinMacro(self)){ if(severity == DEBUG){ Log(DEBUG,"com","sock%03.3d:%s",self->sockHandle,buffer); } else { Log(ERROR,"com","sock%03.3d:%s",self->sockHandle,buffer); } } break; case eWarning: if(!SCinMacro(self)){ if(severity == DEBUG){ Log(DEBUG,"com","sock%03.3d:%s",self->sockHandle,buffer); } else { Log(WARN,"com","sock%03.3d:%s",self->sockHandle,buffer); } } break; case eValue: if(!SCinMacro(self)){ Log(severity,"com","sock%03.3d:%s",self->sockHandle,buffer); } break; default: Log(DEBUG,"sys","Unknown outcode %d detected, FIXME ASAP!!!", iOut); } } /*--------------------------------------------------------------------------*/ int SCNormalWrite(SConnection * self, char *buffer, int iOut) { int i, iPtr, iRet; if (!VerifyConnection(self)) { return 0; } if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) { return 1; /* do not write empty line */ } /* log it for any case */ testAndWriteLog(self, buffer, iOut); testAndStoreInTcl(self, buffer, iOut); testAndWriteSocket(self, buffer, iOut); return 1; } /*--------------------------------------------------------------------------*/ int SCAllWrite(SConnection * self, char *buffer, int iOut) { int i, iPtr, iRet; if (!VerifyConnection(self)) { return 0; } if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) { return 1; /* do not write empty line */ } testAndWriteLog(self, buffer, iOut); testAndStoreInTcl(self, buffer, iOut); doSockWrite(self, buffer); return 1; } /*--------------------------------------------------------------------------*/ int SCACTWrite(SConnection * self, char *buffer, int iOut) { int i, iPtr, iRet; char pBueffel[1024]; char *pPtr = pBueffel; commandContext cx; if (!VerifyConnection(self)) { return 0; } if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) { return 1; /* do not write empty line */ } /* log it for any case */ testAndWriteLog(self, buffer, iOut); testAndStoreInTcl(self, buffer, iOut); /* * copy in ACT */ if (strlen(buffer) + 30 > 1024) { pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char)); memset(pPtr, 0, strlen(buffer) + 20); } sprintf(pPtr, "%d::>%s<::", self->transID, buffer); testAndWriteSocket(self, pPtr, iOut); if (pPtr != pBueffel) { free(pPtr); } return 1; } /*--------------------------------------------------------------------------*/ int SCWriteWithOutcode(SConnection * self, char *buffer, int iOut) { int i, iPtr, iRet, length; char pBueffel[80]; char *bufPtr = NULL; if (!VerifyConnection(self)) { return 0; } if (buffer[0] == '\0' && iOut >= eStart && iOut <= eEvent) { return 1; /* do not write empty line */ } /* log it for any case */ testAndWriteLog(self, buffer, iOut); testAndStoreInTcl(self, buffer, iOut); /* prepare the message with the outcode appended. */ length = strlen(buffer) + strlen(pCode[iOut]) + 10; bufPtr = (char *) malloc(length * sizeof(char)); if (!bufPtr) { Log(ERROR,"sys","%s","out of memory in SCWriteWithOutcode"); return 0; } memset(bufPtr, 0, length * sizeof(char)); strcpy(bufPtr, buffer); i = strlen(bufPtr); while (i-- > 0) { if (!isspace(bufPtr[i])) break; } i++; bufPtr[i] = '\0'; strcat(bufPtr, "@@"); strcat(bufPtr, pCode[iOut]); strcat(bufPtr, "\r\n"); testAndWriteSocket(self, bufPtr, iOut); free(bufPtr); return 1; } /*-------------------------------------------------------------------------*/ static int SCBufferWrite(SConnection * self, char *buffer, int iOut) { if (!VerifyConnection(self)) { return 0; } assert(self->data != NULL); DynStringConcat(self->data, buffer); if (strchr(buffer, '\n') == NULL) { DynStringConcat(self->data, "\n"); } testAndStoreInTcl(self, buffer, iOut); return 1; } /*-------------------------------------------------------------------------*/ int SCStartBuffering(SConnection * pCon) { if (!VerifyConnection(pCon)) { return 0; } if (pCon->data != NULL && pCon->dataOwner == 1) { DeleteDynString(pCon->data); } pCon->data = CreateDynString(128, 128); if (pCon->data == NULL) { return 0; } pCon->oldWriteFunc = pCon->write; pCon->write = SCBufferWrite; pCon->dataOwner = 1; return 1; } /*-------------------------------------------------------------------------*/ pDynString SCEndBuffering(SConnection * pCon) { if (!VerifyConnection(pCon)) { return 0; } assert(pCon->oldWriteFunc != NULL); pCon->write = pCon->oldWriteFunc; pCon->oldWriteFunc = NULL; return pCon->data; } /*--------------------------------------------------------------------------*/ int SCOnlySockWrite(SConnection * self, char *buffer, int iOut) { int i, iPtr, iRet; char pBueffel[80]; if (!VerifyConnection(self)) { return 0; } /* log it for any case */ testAndWriteLog(self,buffer,iOut); testAndStoreInTcl(self, buffer, iOut); testAndWriteSocket(self, buffer, iOut); return 1; } /*--------------------------------------------------------------------------*/ int SCPureSockWrite(SConnection * self, char *buffer, int iOut) { char pBueffel[1024]; char *pPtr; json_object *myJson = NULL; /* for commandlog tail */ if (!VerifyConnection(self)) { return 0; } if(self->iProtocolID == PROTACT) { /* act */ if (strlen(buffer) + 30 > 1024) { pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char)); memset(pPtr, 0, strlen(buffer) + 20); } else { pPtr = pBueffel; } sprintf(pPtr, "%d::>%s<::", self->transID, buffer); testAndWriteSocket(self, pPtr, iOut); if(pPtr != pBueffel){ free(pPtr); } } else if(self->iProtocolID == PROTJSON) { myJson = mkJSON_Object(self,buffer,iOut); if(myJson != NULL){ SCDoSockWrite(self,(char *)json_object_to_json_string(myJson)); json_object_put(myJson); } } else { testAndWriteSocket(self, buffer, iOut); } return 1; } /*-------------------------------------------------------------------------- special for ClientLog. Do not use elsewhere without check ----------------------------------------------------------------------------*/ int SCLogWrite(SConnection * self, char *buffer, int iOut) { char pBueffel[1024]; char *pPtr; json_object *myJson = NULL; if (!VerifyConnection(self)) { return 0; } Log(INFO,"com","sock%03.3d:%s", self->sockHandle, buffer); if(self->iProtocolID == PROTACT) { /* act */ if (strlen(buffer) + 30 > 1024) { pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char)); memset(pPtr, 0, strlen(buffer) + 20); } else { pPtr = pBueffel; } sprintf(pPtr, "%d::>%s<::", self->transID, buffer); testAndWriteSocket(self, pPtr, iOut); if(pPtr != pBueffel){ free(pPtr); } } else if(self->iProtocolID == PROTCODE) { /* withcode */ if (strlen(buffer) + 30 > 1024) { pPtr = (char *) malloc((strlen(buffer) + 30) * sizeof(char)); memset(pPtr, 0, strlen(buffer) + 20); } else { pPtr = pBueffel; } sprintf(pPtr,"%s@@%s",buffer,pCode[iOut]); testAndWriteSocket(self, pPtr, iOut); if(pPtr != pBueffel){ free(pPtr); } } else if(self->iProtocolID == PROTJSON) { /* json */ myJson = mkJSON_Object(self,buffer,iOut); if(myJson != NULL){ SCDoSockWrite(self,(char *)json_object_to_json_string(myJson)); json_object_put(myJson); } } else { testAndWriteSocket(self, buffer, iOut); } return 1; } /*--------------------------------------------------------------------------*/ int SCNotWrite(SConnection * self, char *buffer, int iOut) { int i, iPtr, iRet; char pBueffel[80]; if (!VerifyConnection(self)) { return 0; } /* log it for any case sprintf(pBueffel, "Next line intended for socket: %d", self->sockHandle); SICSLogWrite(pBueffel, eInternal); SICSLogWrite(buffer, iOut); */ testAndStoreInTcl(self, buffer, iOut); return 1; } /*-------------------------------------------------------------------------- This version writes only to configured log files but not to sockets. Used for automatic file execution for the WWW interface */ int SCFileWrite(SConnection * self, char *buffer, int iOut) { int i, iPtr, iRet; char pBueffel[80]; if (!VerifyConnection(self)) { return 0; } /* log it for any case */ testAndWriteLog(self, buffer, iOut); testAndStoreInTcl(self, buffer, iOut); testAndWriteSocket(self, buffer, iOut); return 1; } /*-----------------------------------------------------------------------*/ int SCnoSock(SConnection * self) { if (!VerifyConnection(self)) { return 0; } self->write = SCFileWrite; return 0; } /*------------------------------------------------------------------------*/ int SCWriteUUencoded(SConnection * pCon, char *pName, void *pData, int iDataLen) { void *pPtr = NULL; int iLength = 0; int iRet = 1; FILE *fd; char *pTest; iRet = UUencodeBuffer(pData, iDataLen, pName, &pPtr, &iLength); if (iRet != 1) { SCWrite(pCon, "ERROR: no memory for uuencoder", eError); return 0; } pTest = (char *) pPtr; /* the uuencoder ensures proper telnet */ if (pCon->iTelnet) { ANETwrite(pCon->sockHandle, pPtr, iLength); } else { ANETwrite(pCon->sockHandle, pPtr, iLength); } Log(DEBUG,"com","%s:out:UUData %s %d",ConID(pCon) ,pName, iLength); #ifdef UUDEB fd = fopen("uubuffer.uu", "w"); fputs(pPtr, fd); fclose(fd); #endif free(pPtr); return iRet; } /*------------------------------------------------------------------------*/ #define ZIPBUF 8192 int SCWriteZipped(SConnection * self, char *pName, void *pData, int iDataLen) { char outBuf[65536], *pBuf = NULL, noutBuf[ZIPBUF], *pHeader = NULL; int compressedLength, iRet, iRet2, iCount, protocolID; z_stream compStream; commandContext cc; /* check for a valid connection */ if (!VerifyConnection(self)) { return 0; } /* a telnet connection will corrupt the compressed stream, so stop it! */ if (self->iTelnet) { SCWrite(self, "ERROR: the telnet protocol will corrupt compressed data!", eError); return 0; } /* do nothing if no data */ if (pName == NULL || pData == NULL) { SCWrite(self, "ERROR: no data to write in SCWriteZiped", eError); return 0; } pBuf = malloc(iDataLen*sizeof(char)); memset(pBuf,0,iDataLen*sizeof(char)); compStream.zalloc = (alloc_func) NULL; compStream.zfree = (free_func) NULL; compStream.opaque = (voidpf) NULL; /* iRet = deflateInit(&compStream, Z_DEFAULT_COMPRESSION); */ iRet = deflateInit(&compStream, 1); if (iRet != Z_OK) { sprintf(outBuf, "ERROR: zlib error: %d", iRet); SCWrite(self, outBuf, eError); return 0; } compStream.next_in = (Bytef *) pData; compStream.next_out = (Bytef *) pBuf; compStream.avail_in = iDataLen; compStream.avail_out = iDataLen; iRet = deflate(&compStream, Z_FINISH); if (iRet != Z_STREAM_END && iRet != Z_OK) { sprintf(outBuf, "ERROR: zlib error: %d", iRet); SCWrite(self, outBuf, eError); return 0; } compressedLength = compStream.total_out; /* If data is large, test if we can do it */ if(compressedLength > 2*1000*1024) { if(!ANETcanWrite(self->sockHandle,pData,compressedLength)){ SCWrite(self,"WARNING: skipping excessive data in SCWriteZipped",eLogError); deflateEnd(&compStream); free(pBuf); return 0; } } /* write header line */ memset(outBuf, 0, 65536); protocolID = GetProtocolID(self); if (protocolID == PROTACT) { cc = SCGetContext(self); sprintf(outBuf, "SICSBIN ZIP %s %d %d\r\n", pName, compressedLength, cc.transID); } else { sprintf(outBuf, "SICSBIN ZIP %s %d\r\n", pName, compressedLength); } pHeader = strdup(outBuf); if (pHeader == NULL) { SCWrite(self, "ERROR: out of memory in SCWriteZipped", eError); return 0; } Log(DEBUG,"com", "%s:out:SICSBIN ZIP %s %d", ConID(self), pName, compressedLength); iRet = ANETwrite(self->sockHandle, pHeader, strlen(pHeader)); iRet = ANETwrite(self->sockHandle, pBuf, compStream.total_out); if (iRet != 1) { sprintf(outBuf, "ERROR: network error %d on zipped send", iRet); SCWrite(self, outBuf, eError); return 0; } /* printf("Sent zipped data: %s with %d\n", pHeader, iRet); */ deflateEnd(&compStream); free(pHeader); free(pBuf); return 1; } /*------------------------------------------------------------------*/ int SCWriteBinary(SConnection * self, char *pName, void *pData, int iDataLen) { char outBuf[65536], *pHeader = NULL; int iRet, iRet2, iCount, protocolID; commandContext cc; /* check for a valid connection */ if (!VerifyConnection(self)) { return 0; } /* a telnet connection will corrupt the compressed stream, so stop it! */ if (self->iTelnet) { SCWrite(self, "ERROR: the telnet protocol will corrupt compressed data!", eError); return 0; } /* do nothing if no data */ if (pName == NULL || pData == NULL) { SCWrite(self, "ERROR: no data to write in SCWriteZiped", eError); return 0; } /* If data is large, test if we can do it */ if(iDataLen > 2*1000*1024) { if(!ANETcanWrite(self->sockHandle,pData,iDataLen)){ SCWrite(self,"WARNING: skipping excessive data in SCWriteBinary",eLogError); return 0; } } /* write header line */ memset(outBuf, 0, 65536); protocolID = GetProtocolID(self); if (protocolID == PROTACT) { cc = SCGetContext(self); sprintf(outBuf, "SICSBIN BIN %s %d %d\r\n", pName, iDataLen, cc.transID); } else { sprintf(outBuf, "SICSBIN BIN %s %d\r\n", pName, iDataLen); } pHeader = strdup(outBuf); if (pHeader == NULL) { SCWrite(self, "ERROR: out of memory in SCWriteBinary", eError); return 0; } Log(DEBUG,"com","%s:out:SICSBIN BIN %s %d", ConID(self), pName, iDataLen); iRet = ANETwrite(self->sockHandle, pHeader, strlen(pHeader)); iRet = ANETwrite(self->sockHandle, pData, iDataLen); if (iRet != 1) { sprintf(outBuf, "ERROR: network error %d on zipped send", iRet); SCWrite(self, outBuf, eError); return 0; } /* printf("Sent zipped data: %s with %d\n", pHeader, iRet); */ free(pHeader); return 1; } /*-------------------------------------------------------------------------*/ int SCSendOK(SConnection * self) { return SCWrite(self, "OK", eValue); } /*--------------------------------------------------------------------------*/ int SCRead(SConnection * self, char *buffer, int iLen) { int iRet; if (!VerifyConnection(self)) { return 0; } if (self->sockHandle < 0) { printf("SICS>> "); fgets(buffer, iLen - 1, stdin); return 1; } if (self->sockHandle >= 0) { iRet = ANETread(self->sockHandle, buffer, iLen); if (iRet == 0) { /* no data */ return 0; } else if (iRet < 0) { /* eof */ return EOF; } else { /* data */ return 1; } } else { return EOF; /* fgets(buffer,iLen,stdin); */ } return 1; } /*----------------------------------------------------------------------------*/ int SCMatchRights(SConnection * pCon, int iCode) { char pBueffel[132]; if (!VerifyConnection(pCon)) { return 0; } if (iCode < SCGetRights(pCon)) { sprintf(pBueffel, "ERROR: you are not authorised for this operation"); SCWrite(pCon, pBueffel, eError); return 0; } if (pCon->iGrab) { sprintf(pBueffel, "ERROR: Request refused, control has been grabbed by somebody else"); SCWrite(pCon, pBueffel, eError); return 0; } return 1; } /*----------------------------------------------------------------------------*/ int SCPrompt(SConnection * pCon, char *pPrompt, char *pResult, int iLen) { int iRet, i; char *pPtr = NULL; char pFrom[50]; Status eOld; int oldMode; SConnection *master = NULL; if (!VerifyConnection(pCon)) { return 0; } SCWrite(pCon, pPrompt, eWarning); master = SCfindMaster(pCon); CostaUnlock(master->pStack); while (1) { /* wait a second. We want to wait even in a simulation, otherwise we go into an endless loop. This is why there is the hack with oldMode and pServ->simMode. */ oldMode = pServ->simMode; pServ->simMode = 0; SicsWait(1); pServ->simMode = oldMode; /* is there an interrupt pending ? */ if (SCGetInterrupt(pCon) != eContinue) { break; } /* do we have data ? */ iRet = CostaPop(master->pStack, &pPtr); if (iRet == 1) { CostaLock(master->pStack); strlcpy(pResult, pPtr, iLen); Log(INFO,"sys","prompted%03.3d:", pCon->sockHandle, pPtr); return 1; } } CostaLock(master->pStack); return 0; } /*----------------------------------------------------------------------------*/ int SCPromptTMO(SConnection * pCon, char *pPrompt, char *pResult, int iLen, int timeout) { int iRet, i; char *pPtr = NULL; char pFrom[50]; Status eOld; int oldMode; SConnection *master = NULL; if (!VerifyConnection(pCon)) { return 0; } SCWrite(pCon, pPrompt, eWarning); master = SCfindMaster(pCon); CostaUnlock(master->pStack); for(i = 0; i < timeout; i++) { /* wait a second. We want to wait even in a simulation, otherwise we go into an endless loop. This is why there is the hack with oldMode and pServ->simMode. */ oldMode = pServ->simMode; pServ->simMode = 0; SicsWait(1); pServ->simMode = oldMode; /* is there an interrupt pending ? */ if (SCGetInterrupt(pCon) != eContinue) { break; } /* do we have data ? */ iRet = CostaPop(master->pStack, &pPtr); if (iRet == 1) { CostaLock(master->pStack); strlcpy(pResult, pPtr, iLen); Log(INFO,"com"," prompted%03.3d:", pCon->sockHandle, pPtr); return 1; } } CostaLock(master->pStack); return 0; } /*---------------------------------------------------------------------------*/ int SCGetRights(SConnection * self) { if (!VerifyConnection(self)) { return 0; } return self->iUserRights; } /*---------------------------------------------------------------------------*/ int SCGetGrab(SConnection * self) { if (!VerifyConnection(self)) { return 0; } return self->iGrab; } /*--------------------------------------------------------------------------*/ int SCSetRights(SConnection * self, int iNew) { if (!VerifyConnection(self)) { return 0; } assert(iNew >= usInternal); assert(iNew <= usSpy); self->iUserRights = iNew; return 1; } /*---------------------------------------------------------------------------*/ int SCGetOutClass(SConnection * self) { if (!VerifyConnection(self)) { return 0; } return self->iOutput; } /*--------------------------------------------------------------------------*/ void SCSetInterrupt(SConnection * self, int eCode) { SConnection *pCon = NULL; if (!VerifyConnection(self)) { return; } pCon = SCfindMaster(self); pCon->eInterrupt = eCode; } /*---------------------------------------------------------------------------*/ int SCGetInterrupt(SConnection * self) { SConnection *pCon = NULL; if (!VerifyConnection(self)) { return 0; } pCon = SCfindMaster(self); return pCon->eInterrupt; } /*----------------------------------------------------------------*/ extern char *trim(char *in); /* --------------------------------------------------------------------------*/ int SCInvoke(SConnection * self, SicsInterp * pInter, char *pCommand) { int iRet; long lLen; const char *pResult = NULL; char *pBuffer = NULL, *pFile = NULL; char pBueffel[80]; int i, iSpace; SConnection *pCopy = NULL; if (!VerifyConnection(self)) { return 0; } assert(pInter); /* print to command log if user or manager */ if (SCGetRights(self) <= usUser) { /* * This is a fix to suppress cron messages in the success * case */ if (SCGetWriteFunc(self) != SCNotWrite) { if (self->sockHandle >= 0) { if(strstr(pCommand,"Poch") == NULL){ Log(INFO,"com","sock%03.3d:",self->sockHandle, pCommand); } } else { Log(INFO,"sys","CRON:%s", pCommand); } } } /* invoke */ self->inUse++; self->eInterrupt = eContinue; /* get first word of command */ memset(pBueffel, 0, 80); stptok(trim(pCommand), pBueffel, 79, " "); self->iCmdCtr++; if (self->iCmdCtr > 99998) { self->iCmdCtr = 0; } self->transID = self->iCmdCtr; pCopy = SCCopyConnection(self); if (pCopy == NULL) { SCWrite(self, "ERROR: out of memory in SCInvoke", eError); return 0; } strlcpy(pCopy->deviceID, pBueffel, SCDEVIDLEN); /* do not log the log command; defeats log control */ if(strstr(pCommand,"log ") == NULL) { if(SCGetRights(self) > usUser){ Log(DEBUG,"com","%s:in:%s", ConID(self),pCommand); } else { Log(INFO,"com", "%s:in:%s", ConID(self),pCommand); } } iRet = InterpExecute(pInter, pCopy, pCommand); SCDeleteConnection(pCopy); StatusFileTask(NULL); /* save changed parameters */ self->inUse--; return iRet; } /*--------------------------------------------------------------------------- For configuring connections. Syntax: config OutCode val sets an new output code config Rights User Password sets and verifies new user rights config File Filename Logs to another file config output normal | withcode | ACT Sets output mode config listen 0 | 1 enables commandlog listen mode config remote sets the remote connection flag ---------------------------------------------------------------------------*/ int ConfigCon(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { char pBueffel[512]; char pHost[132]; int i, iRet; int iNum; SConnection *pMaster = NULL; if (!VerifyConnection(pCon)) { return 0; } assert(pSics); /* check no of args */ if (argc < 2) { snprintf(pBueffel,511, "Insufficient number of args to %s", argv[0]); SCWrite(pCon, pBueffel, eError); return 0; } pMaster = SCfindMaster(pCon); /* handle list */ strtolower(argv[1]); if (strcmp(argv[1], "list") == 0) { sprintf(pBueffel, "OutCode = %s\nUserRights = %d", pCode[pCon->iOutput], SCGetRights(pCon)); SCWrite(pCon, pBueffel, eValue); return 1; } else if (strcmp(argv[1], "myname") == 0) { snprintf(pBueffel,511, "MyName = %s", ConName(pCon->ident)); SCWrite(pCon, pBueffel, eValue); return 1; } else if (strcmp(argv[1], "myrights") == 0) { sprintf(pBueffel, "UserRights = %d", SCGetRights(pCon)); SCWrite(pCon, pBueffel, eValue); return 1; } else if (strcmp(argv[1], "listen") == 0) { if (argc < 3) { snprintf(pBueffel, 511, "listen = %d", pCon->listening); SCWrite(pCon, pBueffel, eValue); return 1; } else { pCon->listening = atoi(argv[2]); if (pCon->listening != 0 && pCon->listening != 1) { pCon->listening = 0; SCWrite(pCon, "ERROR: config listen only accepts 0 or 1 as arguments", eError); return 0; } pMaster->listening = pCon->listening; LogListenRegister(pMaster); SCSendOK(pCon); return 1; } } else if(strcmp(argv[1],"remote") == 0) { pMaster->remote = 1; pCon->remote = 1; return 1; } /* check no or args */ if (argc < 3) { snprintf(pBueffel,511, "Insufficient number of args to %s", argv[0]); SCWrite(pCon, pBueffel, eInError); return 0; } if (strcmp(argv[1], "outcode") == 0) { i = 0; strtolower(argv[2]); while (pCode[i] != NULL) { if (strcmp(pCode[i], argv[2]) == 0) { break; } i++; } if (i > iNoCodes) { snprintf(pBueffel,511, "OutCode %s not recognized", argv[2]); SCWrite(pCon, pBueffel, eInError); return 0; } pCon->iOutput = i; pMaster->iOutput = i; SCSendOK(pCon); return 1; } else if (strcmp(argv[1], "output") == 0) { strtolower(argv[2]); if (strcmp(argv[2], "normal") == 0) { SCSetWriteFunc(pCon, SCNormalWrite); SCSetWriteFunc(pMaster, SCNormalWrite); } else if (strcmp(argv[2], "withcode") == 0) { SCSetWriteFunc(pCon, SCWriteWithOutcode); SCSetWriteFunc(pMaster, SCWriteWithOutcode); } else if (strcmp(argv[2], "act") == 0) { SCSetWriteFunc(pCon, SCACTWrite); SCSetWriteFunc(pMaster, SCACTWrite); } else { SCWrite(pCon, "ERROT: output mode not recognised", eError); return 0; } SCSendOK(pCon); return 1; } else if (strcmp(argv[1], "rights") == 0) { if (argc < 4) { snprintf(pBueffel,511, "Insufficient number of args to %s", argv[0]); SCWrite(pCon, pBueffel, eError); return 0; } i = IsValidUser(argv[2], argv[3]); if (i < 0) { snprintf(pBueffel,511, " %s with password ****** is NO valid User on SICS", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } snprintf(pBueffel, 511, "User %s handle %d switched to %d privilege", argv[2], pCon->sockHandle, i); Log(INFO,"sys","%s", pBueffel); pCon->iUserRights = i; pMaster->iUserRights = i; SCWrite(pCon, "Change of Authorisation Acknowledged", eWarning); return 1; } SCWrite(pCon, "Command not recognized", eError); return 0; } /*----------------------------------------------------------------------*/ int SCRegister(SConnection * pCon, SicsInterp * pSics, void *pData, long lID) { pICallBack pInter = NULL; Item sItem; SConnection *pMaster = NULL; pInter = (pICallBack) pData; if (!VerifyConnection(pCon)) { return 0; } assert(pSics); assert(pInter); sItem.lID = lID; sItem.pInterface = pInter; pMaster = SCfindMaster(pCon); LLDnodeAppendFrom(pMaster->iList, &sItem); return 1; } /*----------------------------------------------------------------------*/ int SCUnregister(SConnection * pCon, void *pData) { int iRet; Item sItem; pICallBack pInter; SConnection *pMaster = NULL; if (!VerifyConnection(pCon)) { return 0; } pInter = (pICallBack) pData; pMaster = SCfindMaster(pCon); iRet = LLDnodePtr2First(pMaster->iList); while (iRet != 0) { LLDnodeDataTo(pMaster->iList, &sItem); if (sItem.pInterface == pInter) { LLDnodeDelete(pMaster->iList); LLDnodePtr2Prev(pMaster->iList); } iRet = LLDnodePtr2Next(pMaster->iList); } return 1; } /*----------------------------------------------------------------------*/ int SCUnregisterID(SConnection * pCon, long ID) { int iRet; Item sItem; SConnection *pMaster = NULL; if (!VerifyConnection(pCon)) { return 0; } pMaster = SCfindMaster(pCon); iRet = LLDnodePtr2First(pMaster->iList); while (iRet != 0) { LLDnodeDataTo(pMaster->iList, &sItem); if (sItem.lID == ID) { LLDnodeDelete(pMaster->iList); LLDnodePtr2Prev(pMaster->iList); } iRet = LLDnodePtr2Next(pMaster->iList); } return 1; } /*----------------------------------------------------------------------*/ long SCgetCallbackID(SConnection * pCon, void *pData) { int iRet; Item sItem; pICallBack pInter; SConnection *pMaster = NULL; if (!VerifyConnection(pCon)) { return 0; } pMaster = SCfindMaster(pCon); pInter = (pICallBack) pData; iRet = LLDnodePtr2First(pMaster->iList); while (iRet != 0) { LLDnodeDataTo(pMaster->iList, &sItem); if (sItem.pInterface == pInter) { return sItem.lID; } iRet = LLDnodePtr2Next(pMaster->iList); } return -1; } /*---------------------- The callback data structure --------------------*/ typedef struct { SConnection *pCon; SicsInterp *pSics; char *pAction; } CBAction, *pCBAction; /*---------------------- CBKill -----------------------------------------*/ static void CBKill(void *pData) { pCBAction self = NULL; self = (pCBAction) pData; if (self == NULL) { return; } if (self->pCon) { SCDeleteConnection(self->pCon); } if (self->pAction) { free(self->pAction); } free(self); } /*------------------------------------------------------------------------- The callback function for connection callbacks. Invokes command given at registration time. */ static int ConCallBack(int iEvent, void *pEventData, void *pUserData) { pCBAction self = NULL; self = (pCBAction) pUserData; assert(self); /* check kill condition */ if (self->pCon == NULL) { return -1; } if (self->pAction) { InterpExecute(pServ->pSics, self->pCon, self->pAction); } return 1; } /*--------------------------------------------------------------------------*/ int ConSicsAction(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { SConnection *self = NULL; pICallBack pInterface = NULL; char pBueffel[1024]; pDummy pDum; int iEvent; Item sItem; pCBAction pCB = NULL; CommandList *pCom = NULL; int iMacro; char *script; self = (SConnection *) pData; if (!VerifyConnection(self)) { return 0; } if (argc > 1) { /* put */ if (strcmp(argv[1], "put") == 0) { Arg2Text(argc - 2, &argv[2], pBueffel, 1023); iMacro = SCinMacro(pCon); SCsetMacro(pCon, 0); SCWrite(self, pBueffel, eWarning); SCsetMacro(pCon, iMacro); return 1; } /* register object event action */ if (strcmp(argv[1], "register") == 0) { if (argc < 5) { SCWrite(pCon, "ERROR: Insufficient arguments to register", eError); return 0; } /* get object */ pCom = FindCommand(pSics, argv[2]); if (!pCom) { snprintf(pBueffel,1024, "ERROR: object %s NOT found", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } /* get CallBack interface */ pDum = (pDummy) pCom->pData; assert(pDum); pInterface = (pICallBack) pDum->pDescriptor->GetInterface(pDum, CALLBACKINTERFACE); if (!pInterface) { snprintf(pBueffel,1023, "ERROR: %s does not support CallBacks", argv[2]); SCWrite(pCon, pBueffel, eError); return 0; } /* get Event */ iEvent = Text2Event(argv[3]); if (iEvent < 0) { snprintf(pBueffel,1023, "ERROR: Unknown event code %s", argv[3]); SCWrite(pCon, pBueffel, eError); return 0; } script = Arg2Tcl(argc - 4, &argv[4], NULL, 0); /* now we can install the callback */ pCB = (pCBAction) malloc(sizeof(CBAction)); if (!pCB || !script) { SCWrite(pCon, "ERROR: memory exhausted in SConnection", eError); return 0; } pCB->pCon = SCCopyConnection(pCon); if (!pCB->pCon) { SCWrite(pCon, "ERROR: memory exhausted in SConnection", eError); return 0; } pCB->pSics = pSics; pCB->pAction = script; sItem.pInterface = pInterface; sItem.lID = RegisterCallback(pInterface, iEvent, ConCallBack, pCB, CBKill); LLDnodeAppendFrom(self->iList, &sItem); SCSendOK(pCon); return 1; } } return 0; } static void hookFunc(const char *pText, OutCode eOut, void*pData) { SConnection *pCon = (SConnection *) pData; int text_len = strlen(pText); char txt[5]; if (!VerifyConnection(pCon)) { return; } if (!ANETvalidHandle(pCon->sockHandle)) { return; } snprintf(txt, 5, "%3s:", OutCodeToTxt(eOut)); ANETwrite(pCon->sockHandle, txt, 4); ANETwrite(pCon->sockHandle, (char *)pText, text_len); if (pText[text_len - 1] != '\n') ANETwrite(pCon->sockHandle, "\n", 1); } int KillCapture(SConnection * pCon) { return 1; } /* ------------------------------------------------------------------------ the command function: Syntax: LogOutput [OutCode] Logs with outcode OutCode default eLog -------------------------------------------------------------------------- */ int LogOutput(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { char pBueffel[512]; char *pBuff; int i, result, start; size_t len; OutCode outcode; /* check no af args */ if (argc < 2) { snprintf(pBueffel,sizeof(pBueffel)-1, "Insufficient number of arguments to %s", argv[0]); SCWrite(pCon, pBueffel, eError); return 0; } /* assume default eLog unless told otherwise */ start = 1; outcode = eLog; if (argv[1][0] == '@') { result = OutCodeFromText(&argv[1][1], &outcode); if (result >= 0) { start = 2; } } /* make it a string */ for (i = start, len = 0; i < argc; ++i) len += strlen(argv[i]) + 1; if (len > sizeof(pBueffel)) pBuff = malloc(len+10); else pBuff = pBueffel; if (pBuff == NULL) { SCWrite(pCon, "Out of memory in LogOutput\n", eError); return 1; } for (i = start, len = 0; i < argc; ++i) { if (i > start) pBuff[len++] = ' '; strcpy(&pBuff[len], argv[i]); len += strlen(argv[i]); } Log(INFO,"com","%s",pBuff); if (pBuff != pBueffel) free(pBuff); return 1; } /*--------------------------------------------------------------------------*/ int SCTaskFunction(void *pData) { SConnection *self = NULL; char *pPtr = NULL; int iRet; char *pUser = NULL, *pPassword = NULL; char pHost[132], pBueffel[512]; self = (SConnection *) pData; if (!VerifyConnection(self)) { return 0; } if (self->iEnd) { if (SCActive(self)) { return 1; } else { Log(INFO,"sys","Handle %d disconnected", self->sockHandle); return 0; } } if (!SCisConnected(self)) { self->iEnd = 1; return 1; } /* a timeout check on logins */ if (!self->iLogin && time(NULL) > self->conStart + 120) { ANETclose(self->sockHandle); SCWrite(self, "No valid login in two minutes, closing..", eError); self->iEnd = 1; return 1; } /* pop and execute */ iRet = CostaPop(self->pStack, &pPtr); if (iRet) { if (pPtr) { if (self->iLogin) { /* normal processing, logged in but check for logoff */ if (strstr(pPtr, "logoff") != NULL) { ANETclose(self->sockHandle); self->iEnd = 1; Log(INFO,"sys","Handle %d loging off", self->sockHandle); free(pPtr); return 1; } /* invoke command */ CostaLock(self->pStack); SCInvoke(self, pServ->pSics, pPtr); CostaUnlock(self->pStack); } else { /* response for monit check */ if (strstr(pPtr, "How are you") == pPtr) { SCWrite(self, "I am fine", eError); ANETprocess(); ANETclose(self->sockHandle); self->iEnd = 1; free(pPtr); return 1; } /* check for username and password */ pUser = strtok(pPtr, " \t"); pPassword = strtok(NULL, " \t\r\n"); iRet = IsValidUser(pUser, pPassword); if (iRet >= 0) { SCWrite(self, "Login OK", eLog); self->iLogin = 1; SCSetRights(self, iRet); pHost[0] = '\0'; ANETinfo(self->sockHandle, pHost, 131); snprintf(pBueffel, 511, "Accepted connection %s on socket %d from %s", ConName(self->ident), self->sockHandle, pHost); Log(INFO,"sys","%s",pBueffel); free(pPtr); return 1; } else { SCPrintf(self, eError, "ERROR: Bad login: %s", pPtr); } } free(pPtr); } } if (self->iEnd) { if (SCActive(self)) { return 1; } else { return 0; } } return 1; } /*---------------------------------------------------------------------------*/ void SCSignalFunction(void *pData, int iSignal, void *pSigData) { SConnection *self = NULL; int *iInt; char *pPtr; self = (SConnection *) pData; if (!VerifyConnection(self)) { return; } if (iSignal == SICSINT) { iInt = (int *) pSigData; SCSetInterrupt(self, *iInt); if (*iInt == eEndServer) { self->iEnd = 1; } } else if (iSignal == SICSBROADCAST) { pPtr = (char *) pSigData; if (pPtr != NULL) { SCPureSockWrite(self, pPtr, eWarning); } } else if (iSignal == TOKENRELEASE) { self->iGrab = 0; } else if (iSignal == TOKENGRAB) { self->iGrab = 1; } } /*-----------------------------------------------------------------------*/ void SCparChange(SConnection * self) { StatusFileDirty(); } /*------------------------------------------------------------------------*/ int SCActive(SConnection * self) { if (self->inUse != 0) { return 1; } if (pServ->pExecutor != NULL) { if (GetExeOwner(pServ->pExecutor) == self) { return 1; } } return 0; } /*------------------------------------------------------------------------*/ int SCVerifyConnection(SConnection * self) { return VerifyConnection(self); } /*------------------------------------------------------------------------*/ int SCDoSockWrite(SConnection * self, char *buffer) { return doSockWrite(self, buffer); } /*-------------------------------------------------------------------------*/ int SCPushContext(SConnection * self, int ID, char *deviceID) { commandContext neu; if (!VerifyConnection(self)) { return 0; } neu.transID = ID; strlcpy(neu.deviceID, deviceID, SCDEVIDLEN); LLDnodeAppendFrom(self->contextStack, &neu); return 1; } /*------------------------------------------------------*/ int SCPushContext2(SConnection * self, commandContext cc) { return SCPushContext(self, cc.transID, cc.deviceID); } /*------------------------------------------------------*/ commandContext SCGetContext(SConnection * pCon) { commandContext neu; neu.transID = 0; strcpy(neu.deviceID, "Undefined"); if (!VerifyConnection(pCon)) { return neu; } neu.transID = pCon->transID; strlcpy(neu.deviceID, pCon->deviceID, SCDEVIDLEN); return neu; } /*-----------------------------------------------------*/ int SCPopContext(SConnection * pCon) { if (!VerifyConnection(pCon)) { return 0; } if (LLDnodePtr2Last(pCon->contextStack) != 0) { LLDnodeDelete(pCon->contextStack); } return 1; } /*--------------------------------------------------------*/ int SCGetRunLevel(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->runLevel; } /*--------------------------------------------------------*/ long SCGetIdent(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->ident; } /*--------------------------------------------------------*/ int SCGetSicsError(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->sicsError; } /*--------------------------------------------------------*/ int SCGetTransID(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->transID; } /*--------------------------------------------------------*/ int SCGetProtocolID(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->iProtocolID; } /*--------------------------------------------------------*/ int SCGetSockHandle(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->sockHandle; } /*--------------------------------------------------------*/ int SCGetConStatus(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->conStatus; } /*--------------------------------------------------------*/ char *SCGetDeviceID(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->deviceID; } /*-------------------------------------------------------*/ int SCGetEnd(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return pCon->iEnd; } /*-------------------------------------------------------*/ void SCSetConStatus(SConnection *pCon, int conStatus) { if (!VerifyConnection(pCon)) { return; } pCon->conStatus = conStatus; } /*-------------------------------------------------------*/ void SCSetEventType(SConnection *pCon, int eventType) { if (!VerifyConnection(pCon)) { return; } pCon->conEventType = eventType; } /*-------------------------------------------------------*/ void SCSetSicsError(SConnection *pCon, int sicsError) { if (!VerifyConnection(pCon)) { return; } pCon->sicsError = sicsError; } /*-------------------------------------------------------*/ void SCSetProtocolID(SConnection *pCon, int id) { if (!VerifyConnection(pCon)) { return; } pCon->iProtocolID = id; } /*--------------------------------------------------------*/ void SCCostaLock(SConnection *pCon) { if (!VerifyConnection(pCon)) { return; } CostaLock(pCon->pStack); } /*---------------------------------------------------------*/ void SCCostaUnLock(SConnection *pCon){ if (!VerifyConnection(pCon)) { return; } CostaUnlock(pCon->pStack); } /*---------------------------------------------------------*/ int SCCostaLocked(SConnection *pCon) { if (!VerifyConnection(pCon)) { return 0; } return CostaLocked(pCon->pStack); } /*----------------------------------------------------------*/ int SCCostaTop(SConnection *pCon, char *command) { if (!VerifyConnection(pCon)) { return 0; } return CostaTop(pCon->pStack, command); } /*----------------------------------------------------------*/ void SCSetGrab(SConnection *pCon, int iGrab) { if (!VerifyConnection(pCon)) { return; } 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; }