//Copyright (c) Microsoft Corporation. All rights reserved. /**************************************************************************** FILE: NetIO.c Functions for connecting to machines and handling data transfers between machines. TABS: Set for 4 spaces. ****************************************************************************/ #include #include // required for all Windows applications #include #include #pragma warning (disable: 4201) // disable "nonstandard extension used : nameless struct/union" #include #pragma warning (default: 4201) #include #include "WinTel.h" // specific to this program #include "commands.h" #include "debug.h" #pragma warning( disable : 4100 ) #ifdef USETCP #include "telnet.h" #endif char *rgchTermType[] = { "ANSI", "VT100", "VT52", "VTNT" }; extern void NTLMCleanup(); extern BOOL DoNTLMAuth(WI *pwi, PUCHAR pBuffer, DWORD dwSize); extern int SafeSetSocketOptions(SOCKET s); BOOL g_fSentWillNaws = FALSE; static BOOL FAttemptServerConnect(WI *pwi, LPSTR, LPNETDATA); static void xfGetData(char, char *, DWORD, int); #ifdef USETCP #ifdef TELXFER static DWORD xfGetSomeData(char *, DWORD, int); #endif //TELXFER #endif //USETCP static void xfPutc(char, int); static int term_inx = 0; extern BOOL StartNTLMAuth(WI *); extern TCHAR szUserName[ UNLEN + 1 ]; extern CHAR* szUser; TCHAR szCombinedFailMsg [255]; extern HANDLE g_hControlHandlerEvent; extern HANDLE g_hCaptureConsoleEvent; extern HANDLE g_hAsyncGetHostByNameEvent; extern HANDLE g_hRemoteNEscapeModeDataSync; extern BOOL g_fConnectFailed; void GetErrMsgString( DWORD dwErrNum, LPTSTR *lpBuffer ) { DWORD dwStatus = 0; LCID old_thread_locale; switch (GetACP()) { // for Hebrew and arabic winerror.h is not localized..so get the english one for all these case 1256: case 1255: old_thread_locale = GetThreadLocale(); SetThreadLocale( MAKELCID( MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT ) ); break; default: old_thread_locale = -1; } dwStatus = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwErrNum, LANG_NEUTRAL, ( LPTSTR )lpBuffer, 0, NULL ); if( !dwStatus ) { *lpBuffer = NULL; } if (old_thread_locale != -1) { SetThreadLocale(old_thread_locale); } return; } BOOL FConnectToServer(WI *pwi, LPSTR szHostName, LPNETDATA lpData) { BOOL fResult; // Before we Connect we make sure we are not connected. // This ASSERT should never blowup !! ASSERT(fConnected==FALSE); // We initialize stuff for this connection. pwi->trm.SentTermType = TT_UNKNOWN; pwi->trm.CurrentTermType = TT_ANSI; /* this is our default term type*/ fResult = FAttemptServerConnect(pwi, szHostName, lpData); if( fResult != TRUE ) { TCHAR szStr[ cchMaxHostName ]; g_fConnectFailed = TRUE; if( g_szPortNameOrNo[ 0 ] == 0 ) { _sntprintf( g_szPortNameOrNo,cchMaxHostName-1,( LPCTSTR )L"%d", rgService ); } _sntprintf( szStr, cchMaxHostName -1 ,szOnPort, g_szPortNameOrNo ); _sntprintf(szCombinedFailMsg,ARRAY_SIZE(szCombinedFailMsg)-1,_T("%s%s"),szConnectFailedMsg,szStr); g_szPortNameOrNo[ 0 ] = 0; if( g_dwSockErr == 0 ) { //Not an error we want to inform abt ErrorMessage( szCombinedFailMsg, szConnectFailed ); } else { DWORD dwWritten = 0; LPTSTR lpBuffer = NULL; GetErrMsgString( g_dwSockErr, &lpBuffer ); if( lpBuffer ) { ConnectTimeErrorMessage( szCombinedFailMsg, lpBuffer ); LocalFree( lpBuffer ); } else { ErrorMessage( szCombinedFailMsg, szConnectFailed ); } } } return fResult; } #ifdef USETCP /*** FPostReceive - post an asynchronous receive */ BOOL FPostReceive(LPNETDATA lpData) { #ifdef NBTEST OutputDebugString("PostReceive In\n"); #endif #ifdef NBTEST OutputDebugString("PostReceive Out\n"); #endif return TRUE; } int FWriteToNet(WI *pwi, LPSTR addr, int cnt) { int len = 0, retries = 0; if(pwi->nd.hsd == INVALID_SOCKET) { len = SOCKET_ERROR; goto Done; } do { len = send( pwi->nd.hsd, addr, cnt, 0 ); retries ++; } while ((len == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK) && (retries < 5)); Done: return(len); } BOOL FCommandPending(WI *pwi) { return(FALSE); } /* void FSendTM( HWND hwnd ) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); unsigned char sbuf[] = { IAC, DO, TO_TM }; ui.fFlushOut = 1; send( pwi->nd.hsd, ( char * )sbuf, sizeof( sbuf ), 0); } */ //Our server still doesn't support urgent data handling.. void FSendSynch(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); unsigned char sbuf[] = { IAC, DM }; send( pwi->nd.hsd, ( char * )sbuf, 1, 0 ); send( pwi->nd.hsd, ( char * )( sbuf + 1 ), 1, MSG_OOB ); } void FSendTelnetCommands( HWND hwnd, char chCommand ) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); unsigned char sbuf[]={ IAC , 0 }; sbuf[1] = chCommand; send( pwi->nd.hsd, ( char * )sbuf, sizeof( sbuf ), 0 ); } void FSendChars(HWND hwnd, WCHAR rgchChar[], int iLength ) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); CHAR rgchMBChar[ SMALL_STRING ]; iLength = WideCharToMultiByte( GetConsoleCP(), 0, rgchChar, iLength, rgchMBChar, (SMALL_STRING - sizeof(CHAR)), NULL, NULL ); send( pwi->nd.hsd, rgchMBChar, iLength, 0 ); } void FDisableFlush(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); if (ui.fFlushOut) { ui.fFlushOut = 0; DoIBMANSIOutput(pwi, &pwi->trm, strlen( ( CHAR * ) szNewLine), szNewLine); #ifdef TCPTEST OutputDebugString("Disable Flush\n"); #endif } } void FProcessDont(WI *pwi, LPSTR *ps) { unsigned char sbuf[16]; sbuf[0] = IAC; sbuf[1] = WONT; switch (*(unsigned char FAR *)(*ps)) { default: sbuf[2] = *(unsigned char FAR *)(*ps); break; } FWriteToNet(pwi, ( char* )sbuf, 3); if( *(*ps) == TO_NAWS ) { g_bDontNAWSReceived = TRUE; } } void DoNawsSubNegotiation( WI *pwi ) { unsigned char sbuf[16]; INT iIndex = 0; sbuf[iIndex++] = IAC; sbuf[iIndex++] = SB; sbuf[iIndex++] = TO_NAWS; sbuf[iIndex++] = 0; sbuf[iIndex++] = ( UCHAR ) ( (pwi->sbi.srWindow.Right - pwi->sbi.srWindow.Left) + 1 ) ; sbuf[iIndex++] = 0; sbuf[iIndex++] = ( UCHAR )( ( pwi->sbi.srWindow.Bottom - pwi->sbi.srWindow.Top ) + 1 ); sbuf[iIndex++] = IAC; sbuf[iIndex++] = SE; FWriteToNet(pwi, ( char* )sbuf, iIndex ); } void FProcessDo(WI *pwi, LPSTR *ps) { unsigned char sbuf[16]; BOOL bWriteToNet = TRUE; sbuf[0] = IAC; sbuf[1] = WONT; switch (*(unsigned char FAR *)(*ps)) { case TO_NEW_ENVIRON: sbuf[1] = WILL; sbuf[2] = TO_NEW_ENVIRON; break; case TO_NAWS: { INT iIndex = 1; if( !g_fSentWillNaws ) { sbuf[iIndex++] = WILL; sbuf[iIndex++] = TO_NAWS; FWriteToNet(pwi, ( char* )sbuf, iIndex ); g_fSentWillNaws = TRUE; } DoNawsSubNegotiation( pwi ); pwi->nd.fRespondedToDoNAWS = TRUE; bWriteToNet = FALSE; } break; case TO_ECHO: sbuf[1] = WILL; sbuf[2] = TO_ECHO; break; case TO_BINARY: sbuf[1] = WILL; sbuf[2] = TO_BINARY; break; case TO_TERM_TYPE: /* terminal type */ sbuf[1] = WILL; sbuf[2] = TO_TERM_TYPE; if( !pwi->nd.fRespondedToDoNAWS && !g_fSentWillNaws ) { sbuf[3] = IAC; sbuf[4] = WILL; sbuf[5] = TO_NAWS; bWriteToNet = FALSE; FWriteToNet(pwi, ( char* )sbuf, 6); g_fSentWillNaws = TRUE; } // haven't sent the termtype over yet. pwi->trm.SentTermType = TT_UNKNOWN; break; case TO_AUTH: if( pwi->nd.fRespondedToDoAUTH ) return; if( ui.bWillAUTH ) sbuf[1] = WILL; sbuf[2] = TO_AUTH; pwi->nd.fRespondedToDoAUTH = TRUE; break; case TO_SGA: // will SUPPRESS-GO-AHEAD sbuf[1] = WILL; sbuf[2] = TO_SGA; break; default: sbuf[2] = *(unsigned char FAR *)(*ps); break; } if ( bWriteToNet ) { FWriteToNet(pwi, ( char* )sbuf, 3); } } void FProcessWont(WI *pwi, LPSTR *ps) { unsigned char sbuf[16]; sbuf[0] = IAC; sbuf[1] = DONT; switch (*(unsigned char FAR *)(*ps)) { case TO_ECHO: sbuf[2] = TO_ECHO; break; case TO_TERM_TYPE: sbuf[2] = TO_TERM_TYPE; break; case TO_TM: FDisableFlush(pwi->hwnd); return; default: sbuf[2] = *(unsigned char FAR *)(*ps); break; } FWriteToNet(pwi, ( char* )sbuf, 3); } void FProcessWill(WI *pwi, LPSTR *ps) { unsigned char sbuf[16]; BOOL bWriteToNet = TRUE; sbuf[0] = IAC; sbuf[1] = DONT; switch (*(unsigned char FAR *)(*ps)) { case TO_ECHO: if( pwi->nd.fRespondedToWillEcho ) return; sbuf[1] = DO; sbuf[2] = TO_ECHO; pwi->nd.fRespondedToWillEcho = TRUE; break; case TO_TM: FDisableFlush(pwi->hwnd); return; case TO_SGA: if( pwi->nd.fRespondedToWillSGA ) return; sbuf[1] = DO; sbuf[2] = TO_SGA; pwi->nd.fRespondedToWillSGA = TRUE; break; case TO_BINARY: sbuf[1] = DO; sbuf[2] = TO_BINARY; break; #if 0 case TO_NTLM: if ( pwi->nd.fRespondedToWillNTLM ) return; if ( ui.bDoNTLM ) sbuf[1] = DO; sbuf[2] = TO_NTLM; pwi->nd.fRespondedToWillNTLM = TRUE; if ( ui.bDoNTLM ) { bWriteToNet = FALSE; FWriteToNet(pwi, sbuf, 3); StartNTLMAuth(pwi); } break; #endif default: sbuf[2] = *(unsigned char FAR *)(*ps); break; } if ( bWriteToNet ) FWriteToNet(pwi, ( char* )sbuf, 3); } BOOL StuffEscapeIACs( PUCHAR* ppBufDest, UCHAR bufSrc[], DWORD* pdwSize ) { size_t length; int cursorDest = 0; int cursorSrc = 0; BOOL found = FALSE; PUCHAR pDest = NULL; if( *pdwSize <= 0 ) { return ( found ); } //get the location of the first occurrence of IAC pDest = (PUCHAR) memchr( bufSrc, IAC, *pdwSize ); //attack? pdwsize could not be traced back to see if it's always valid. if( pDest == NULL ) { return ( found ); } *ppBufDest = (PUCHAR) malloc( *pdwSize * 2 ); if( *ppBufDest == NULL ) { ASSERT( ( 0, 0 ) ); return ( found ); } while( pDest != NULL ) { //copy data upto and including that point length = (pDest - ( bufSrc + cursorSrc)) + 1 ; memcpy( *ppBufDest + cursorDest, bufSrc + cursorSrc, length ); //attack? length could not be traced back to see if it's always valid. cursorDest += length; //stuff another TC_IAC (*ppBufDest)[ cursorDest ] = IAC; cursorDest++; cursorSrc += length; pDest = (PUCHAR) memchr( bufSrc + cursorSrc, IAC, *pdwSize - cursorSrc ); //attack? pdwsize could not be traced back to see if it's always valid. } //copy remaining data memcpy( *ppBufDest + cursorDest, bufSrc + cursorSrc, *pdwSize - cursorSrc ); //attack? pdwsize could not be traced back to see if it's always valid. if( cursorDest ) { *pdwSize += cursorDest - cursorSrc; found = TRUE; } return ( found ); } INT GetVariable( UCHAR rgchBuffer[], CHAR szVar[] ) { INT iIndex = 0; INT iVarIndex = 0; while( iIndex < MAX_BUFFER_SIZE && iVarIndex < MAX_STRING_LENGTH && rgchBuffer[ iIndex ] != VAR && rgchBuffer[ iIndex ] != USERVAR && ( !( rgchBuffer[ iIndex ] == IAC && rgchBuffer[ iIndex + 1 ] == SE ) ) ) { if( rgchBuffer[ iIndex ] == ESC ) { //ignore ESC and take the next char as part of name iIndex++; } szVar[ iVarIndex++ ] = rgchBuffer[ iIndex++ ]; } szVar[ iVarIndex ] = 0; return iIndex; } void PutDefaultVarsInBuffer( UCHAR ucBuffer[], INT *iIndex ) { ASSERT( iIndex ); if( wcscmp( szUserName, ( LPTSTR )L"" ) != 0 ) { DWORD dwNum; ASSERT( szUser ); if( *iIndex + ( strlen( USER ) + 1 ) + ( strlen( szUser ) + 1 ) + ( strlen( SYSTEMTYPE ) + 1 ) + ( strlen( WIN32_STRING ) + 1 ) > MAX_STRING_LENGTH ) { ASSERT( 0 ); return; } { //variable USER ucBuffer[ ( *iIndex )++ ] = VAR; strcpy( ucBuffer + ( *iIndex ), USER ); //no overflow. USER is const char * *iIndex = *iIndex + strlen( USER ) ; ucBuffer[ ( *iIndex )++ ] = VALUE; strcpy(ucBuffer+( *iIndex ), szUser ); //no overflow. SzUser is valid, NULL terminated. *iIndex = ( *iIndex ) + strlen( szUser); } { //variable SYSTEMTYPE ucBuffer[( *iIndex )++] = VAR; strcpy(ucBuffer+( *iIndex ), SYSTEMTYPE ); //no overflow. SYSTEMTYPE is const char * *iIndex = ( *iIndex ) + strlen( SYSTEMTYPE ); ucBuffer[( *iIndex )++] = VALUE; strcpy(ucBuffer+( *iIndex ), WIN32_STRING );//no overflow. WIN32_STRING is const char * *iIndex = ( *iIndex ) + strlen( WIN32_STRING ); } } return; } void FProcessSB(WI * pwi, LPSTR *ps, int *recvsize) { unsigned char sbuf[16]; int inx; int i = 0; int cbLeft = *recvsize; // // Is the end of this option in the receive buffer? // while ( cbLeft ) { if ( ((unsigned char) (*ps)[i]) == (unsigned char) SE ) goto Found; cbLeft--; i++; } // // We ran out of buffer before finding the end of the option. IAC and // SB were already eaten so add them // #ifdef TCPTEST OutputDebugString("FProcessSB: saving incomplete option for next recv\n"); #endif pwi->nd.lpTempBuffer[0] = (unsigned char) IAC; pwi->nd.lpTempBuffer[1] = (unsigned char) SB; for ( i = 2, cbLeft = (*recvsize+2); i < cbLeft; i++ ) pwi->nd.lpTempBuffer[i] = (*ps)[i-2]; pwi->nd.cbOld = *recvsize + 2; *recvsize = 0; return; Found: switch (*(unsigned char FAR *)(*ps)) { case TO_NEW_ENVIRON: //MBSC user name value now available in szUser if( *(unsigned char FAR *)(*ps+1) == TT_SEND ) { PUCHAR ucServerSentBuffer = *ps; UCHAR ucBuffer[ MAX_BUFFER_SIZE + 2 ]; int iIndex = 0; ucBuffer[ iIndex++ ] = ( UCHAR )IAC; ucBuffer[ iIndex++] = ( UCHAR )SB; ucBuffer[ iIndex++] = TO_NEW_ENVIRON; ucBuffer[ iIndex++] = TT_IS; inx = iIndex; if( *(unsigned char FAR *)(ucServerSentBuffer+2) == IAC && *(unsigned char FAR *)(ucServerSentBuffer+3) == SE ) { PutDefaultVarsInBuffer( ucBuffer, &inx ); } else { ucServerSentBuffer = ucServerSentBuffer + 2 ; // eat TO_NEW_ENVIRON, TT_SEND while ( !( *ucServerSentBuffer == IAC && *(ucServerSentBuffer+1) == SE ) && inx < MAX_BUFFER_SIZE ) { CHAR szVar[ MAX_STRING_LENGTH ]; CHAR *pcVal = NULL; switch( *(unsigned char FAR *)(ucServerSentBuffer) ) { case VAR: ( ucServerSentBuffer )++; //eat VAR if( ( *ucServerSentBuffer == IAC && *(ucServerSentBuffer+1) == SE ) || *ucServerSentBuffer == USERVAR ) { //send defaults PutDefaultVarsInBuffer( ucBuffer, &inx ); } else { ucServerSentBuffer += GetVariable( ucServerSentBuffer, szVar ); //GetVariable returns consumed net data if( inx + strlen( szVar ) + 1 < MAX_BUFFER_SIZE ) { ucBuffer[ inx++ ] = VAR; //copy name of the variable strncpy( ucBuffer+inx, szVar, MAX_BUFFER_SIZE - inx); inx += strlen( szVar ); } //now copy the value if defined if( strcmp( szVar, USER ) == 0 ) { if( inx + strlen( szUser ) + 1 < MAX_BUFFER_SIZE ) { ucBuffer[inx++] = VALUE; strncpy(ucBuffer+inx, szUser, MAX_BUFFER_SIZE - inx ); inx = inx + strlen( szUser); } } else if( strncmp( szVar, SYSTEMTYPE, strlen( SYSTEMTYPE ) ) == 0 ) { if( inx + strlen( WIN32_STRING ) + 1 < MAX_BUFFER_SIZE ) { ucBuffer[inx++] = VALUE; strncpy(ucBuffer+ inx, WIN32_STRING,MAX_BUFFER_SIZE - inx ); inx = inx + strlen( WIN32_STRING ); } } else { //do nothing. It means, variable is undefined } } break; case USERVAR: ( ucServerSentBuffer )++; //eat USERVAR if( ( *ucServerSentBuffer == IAC && *(ucServerSentBuffer+1) == SE ) || *ucServerSentBuffer == VAR ) { //send defaults ie; NONE } else { //Send the variable that is asked for DWORD dwSize = 0; ucServerSentBuffer += GetVariable( ucServerSentBuffer, szVar ); if( inx + strlen( szVar ) + 1 < MAX_BUFFER_SIZE ) { ucBuffer[inx++] = USERVAR; strncpy( ucBuffer+inx, szVar,MAX_BUFFER_SIZE - inx ); inx += strlen( szVar ); } dwSize = GetEnvironmentVariableA( szVar, NULL, 0 ); if( dwSize > 0 ) { pcVal = ( CHAR * ) malloc( dwSize + DELTA ); //This delta is meant for //holding any ESC chars if( !pcVal ) { return; } if( GetEnvironmentVariableA( szVar, pcVal, dwSize ) ) { INT x = 0; INT iNeedForEsc = 0; CHAR cVar = VAR, cUserVar = USERVAR; x = strlen( pcVal ) - 1; while( x >= 0 ) { if( pcVal[ x ] >= cVar && pcVal[ x ] <= cUserVar ) { //needs an ESC char iNeedForEsc++; } x--; } if( iNeedForEsc && iNeedForEsc < DELTA ) { x = strlen( pcVal ); //Null char is same as of VAR. So, special case. pcVal[ x + iNeedForEsc ] = pcVal[ x-- ]; while( x >= 0 ) { pcVal[ x + iNeedForEsc ] = pcVal[ x ]; if( pcVal[ x ] >= cVar && pcVal[ x ] <= cUserVar ) { //needs an ESC char iNeedForEsc--; pcVal[ x + iNeedForEsc ] = ESC; } x--; } } if( inx + strlen( pcVal ) + 1 < MAX_STRING_LENGTH ) { //write VALUE keyword ucBuffer[inx++] = VALUE; //write actual value strncpy(ucBuffer+ inx, pcVal,MAX_BUFFER_SIZE - inx ); inx = inx + strlen( pcVal ); } } free( pcVal ); } } break; default: ASSERT( 0 ); //This should not happen. Only types we know are VAR and USERVAR break; } } } ucBuffer[inx++] = ( UCHAR )IAC; ucBuffer[inx++] = ( UCHAR )SE; FWriteToNet(pwi, ucBuffer, inx); } break; case TO_TERM_TYPE: // This is guaranteed to happen after an authentication has happened so we can start obeying the // local echo settings... ui.fDebug |= ui.honor_localecho; // restore the saved echo settings. if( *(unsigned char FAR *)(*ps+1) == TT_SEND ) { sbuf[0] = IAC; sbuf[1] = SB; sbuf[2] = TO_TERM_TYPE; sbuf[3] = TT_IS; inx = 4; if( pwi->trm.SentTermType == TT_UNKNOWN && pwi->trm.RequestedTermType != TT_UNKNOWN ) { // we haven't started the negotiation yet and the user has specified // a preferred term type, so we start with that. // RequestedTermType here is the user's setting not the server's. pwi->trm.CurrentTermType = pwi->trm.RequestedTermType; pwi->trm.FirstTermTypeSent = pwi->trm.CurrentTermType; } else { pwi->trm.CurrentTermType = (pwi->trm.CurrentTermType + 1) % 4; if( pwi->trm.CurrentTermType == pwi->trm.FirstTermTypeSent ) pwi->trm.CurrentTermType = pwi->trm.SentTermType; } //write maximum number of n bytes where n = sizeof(sbuf)-CurrentLength(sbuf)-2BytesForIACandSE-1ForNULL strncpy( (char *) sbuf+4, rgchTermType[pwi->trm.CurrentTermType],16 - strlen(sbuf) -2 -1); inx += strlen(rgchTermType[pwi->trm.CurrentTermType]); sbuf[inx++] = IAC; sbuf[inx++] = SE; // set the Sent TermType to what we just sent pwi->trm.SentTermType = pwi->trm.CurrentTermType ; FWriteToNet(pwi, ( char * )sbuf, inx); } break; #if 1 case TO_AUTH: if( (*(unsigned char FAR *)(*ps+1) == AU_SEND) && (*(unsigned char FAR *)(*ps+2) == AUTH_TYPE_NTLM) ) { if ( pwi->eState!= Connecting || !PromptUser() || !StartNTLMAuth(pwi) ) { // there has been an error. pwi->eState = Telnet; sbuf[0] = IAC; sbuf[1] = SB; sbuf[2] = TO_AUTH; sbuf[3] = AU_IS; sbuf[4] = AUTH_TYPE_NULL; sbuf[5] = 0; sbuf[6] = IAC; sbuf[7] = SE; FWriteToNet(pwi, ( char * )sbuf, 8); } } else if( (*(unsigned char FAR *)(*ps+1) == AU_REPLY) && (*(unsigned char FAR *)(*ps+2) == AUTH_TYPE_NTLM) ) { // ps + 3 is the modifier and for NTLM it is AUTH_CLIENT_TO_SERVER & AUTH_ONE_WAY. // ps + 4 is the NTLM accept or NTLM challenge or NTLM reject switch ( *(unsigned char FAR *)(*ps+4) ) { case NTLM_CHALLENGE: if( pwi->eState != Authenticating || !DoNTLMAuth(pwi, (unsigned char FAR *)(*ps+5), *recvsize-5) ) { // there has been an error. pwi->eState = Telnet; sbuf[0] = IAC; sbuf[1] = SB; sbuf[2] = TO_AUTH; sbuf[3] = AU_IS; sbuf[4] = AUTH_TYPE_NULL; sbuf[5] = 0; sbuf[6] = IAC; sbuf[7] = SE; FWriteToNet(pwi, ( char * )sbuf, 8); } break; case NTLM_ACCEPT: //fall through case NTLM_REJECT: //fall through default: pwi->eState = Telnet; if( pwi->eState == Authenticating || pwi->eState == AuthChallengeRecvd ) { NTLMCleanup(); } break; } } else { pwi->eState = Telnet; sbuf[0] = IAC; sbuf[1] = SB; sbuf[2] = TO_AUTH; sbuf[3] = AU_IS; sbuf[4] = AUTH_TYPE_NULL; sbuf[5] = 0; sbuf[6] = IAC; sbuf[7] = SE; FWriteToNet(pwi, ( char * )sbuf, 8); } break; #endif default: break; } while (*(unsigned char FAR *)(*ps) != SE) { (*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 1; } // // Do one more to step over the SE // (*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 1; } void FProcessIAC( HWND hwnd, WI * pwi, LPSTR * ps, LPSTR * pd, int * recvsize, int * t_size) { UCHAR ch = *(unsigned char FAR *)(*ps); ui.nottelnet = FALSE; // We can safely say that we are talking to a telnet server now... // // The IAC has already been subtracted from *recvsize // // // Make sure we have enough recv buffer to process the rest of the IAC // We know the DO, DONT etc. options always take two bytes plus the IAC. // if ( ((ch == DONT || ch == DO || ch == WILL || ch == WONT) && *recvsize < 2) || (ch != SB && *recvsize < 1) ) { int i; #ifdef TCPTEST OutputDebugString("FProcessIAC: saving incomplete option for next recv\n"); #endif // // IAC was previously eaten // pwi->nd.lpTempBuffer[0] = (unsigned char) IAC; for ( i = 1; i < (*recvsize+1); i++ ) pwi->nd.lpTempBuffer[i] = (*ps)[i-1]; pwi->nd.cbOld = *recvsize + 1; *recvsize = 0; return; } switch (*(unsigned char FAR *)(*ps)) { case DONT: (*ps) = (char FAR *)(*ps) + 1; /* process options */ FProcessDont(pwi, ps); #ifdef TCPTEST OutputDebugString("DONT \n"); #endif (*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 2; break; case DO: (*ps) = (char FAR *)(*ps) + 1; /* process options */ FProcessDo(pwi, ps); #ifdef TCPTEST OutputDebugString("DO \n"); #endif (*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 2; break; case WONT: (*ps) = (char FAR *)(*ps) + 1; /* process options */ FProcessWont(pwi, ps); #ifdef TCPTEST OutputDebugString("WONT \n"); #endif (*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 2; break; case WILL: (*ps) = (char FAR *)(*ps) + 1; /* process options */ FProcessWill(pwi, ps); #ifdef TCPTEST OutputDebugString("WILL \n"); #endif (*ps) = (char FAR *)(*ps) + 1; *recvsize = *recvsize - 2; break; case SB: (*ps) = (char FAR *)(*ps) + 1; *recvsize -= 1; /* process options */ FProcessSB(pwi, ps, recvsize); break; default: (*ps) = (char FAR *)(*ps) + 1; *recvsize -= 1; break; } } #ifdef TCPTEST VOID DumpBuffer( VOID FAR * pbuff, DWORD cb ) { #define NUM_CHARS 16 DWORD i, limit; CHAR TextBuffer[NUM_CHARS + 1]; LPBYTE BufferPtr; if ( !pbuff ) { OutputDebugString("No buffer\n"); return; } BufferPtr = (LPBYTE) pbuff; // // Hex dump of the bytes // limit = ((cb - 1) / NUM_CHARS + 1) * NUM_CHARS; for (i = 0; i < limit; i++) { if (i < cb) { snprintf(DebugBuffer,sizeof(DebugBuffer)-1, "%02x ", BufferPtr[i]); OutputDebugString( DebugBuffer ); if (BufferPtr[i] < 31 ) { TextBuffer[i % NUM_CHARS] = '.'; } else if (BufferPtr[i] == '\0') { TextBuffer[i % NUM_CHARS] = ' '; } else { TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i]; } } else { OutputDebugString(" "); TextBuffer[i % NUM_CHARS] = ' '; } if ((i + 1) % NUM_CHARS == 0) { TextBuffer[NUM_CHARS] = 0; snprintf(DebugBuffer,sizeof(DebugBuffer)-1, " %s\n", TextBuffer); OutputDebugString( DebugBuffer ); } } } #endif void FProcessSessionData( int cBytes, PUCHAR pchNBBuffer, WI *pwi ) { WaitForSingleObject( g_hCaptureConsoleEvent, INFINITE ); WaitForSingleObject( g_hRemoteNEscapeModeDataSync, INFINITE ); if( pwi->hOutput != g_hSessionConsoleBuffer ) { pwi->hOutput = g_hSessionConsoleBuffer; SetConsoleActiveScreenBuffer(g_hSessionConsoleBuffer); } /*This is needed so that we don't write data to the session even after disconnection of client */ if( !fConnected ) { return; } ResetEvent( g_hRemoteNEscapeModeDataSync ); if( pwi->trm.CurrentTermType == TT_VTNT ) { if( !DoVTNTOutput(pwi, &pwi->trm, cBytes, pchNBBuffer) ) { // // The following two lines were originally added as a // mechanism of defaulting to VT100 in case of some servers // accepting VTNT, during term type negotiation, even though // in reality they do not support VTNT. Specifically, Linux // was showing this behavior during our testing. But the // function DoVTNTOutput returns FALSE even in other cases // such as, when we get some junk data from the server. In // such cases we should not call DoIBMANSIOutput (bug 1119). // pwi->trm.CurrentTermType = TT_ANSI; DoIBMANSIOutput(pwi, &pwi->trm, cBytes, pchNBBuffer); } } else { DoIBMANSIOutput(pwi, &pwi->trm, cBytes, pchNBBuffer); } pwi->ichTelXfer = 0; SetEvent( g_hRemoteNEscapeModeDataSync ); } void FProcessFDRead(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); int recvsize, t_size; LPSTR ps, pd; // // pwi->nd.cbOld Is the number of bytes left over from the previous // packet that we kept in pwi->nd.lpTempBuffer // if ((recvsize=recv(pwi->nd.hsd, pwi->nd.lpTempBuffer + pwi->nd.cbOld, READ_BUF_SZ - pwi->nd.cbOld, 0)) < 0) { return; } // // Fix to bug 284 // Sleep(0); recvsize += pwi->nd.cbOld; pwi->nd.cbOld = 0; ps = pwi->nd.lpTempBuffer; pd = pwi->nd.lpReadBuffer; t_size = 0; while( recvsize-- ) { if( *(unsigned char FAR *) ps == (unsigned char)IAC ) { if( recvsize == 0 ) { pwi->nd.lpTempBuffer[0] = (unsigned char) IAC; pwi->nd.cbOld = 1; break; } ps++; if( *(unsigned char FAR *)ps == (unsigned char)IAC ) { // // This was an escaped IAC so put it in the normal // input buffer // ps++; *(unsigned char FAR *)pd = (unsigned char)IAC; pd++; recvsize--; t_size++; } else { FProcessIAC(hwnd, pwi, &ps, &pd, &recvsize, &t_size); } } else { *(char FAR *)pd = *(char FAR *)ps; pd++; ps++; t_size++; } } if( t_size ) { /* add received data to buffer */ if ( !(ui.fFlushOut) || ui.nottelnet ) { FProcessSessionData( t_size, pwi->nd.lpReadBuffer, pwi ); } } } void FProcessFDOOB(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); int recvsize; LPSTR ps; if ((recvsize=recv(pwi->nd.hsd, pwi->nd.lpTempBuffer, READ_BUF_SZ, MSG_OOB)) < 0) { #ifdef TCPTEST OutputDebugString("recv error \n"); #endif return; } ps = pwi->nd.lpTempBuffer; if (*(unsigned char *)ps == (unsigned char)DM) { #ifdef TCPTEST OutputDebugString("DM received\n"); #endif FDisableFlush(hwnd); } } BOOL FAttemptServerConnect(WI *pwi, LPSTR szHostName, LPNETDATA lpData) { BOOL got_connected = FALSE; struct servent *serv; struct sockaddr_storage myad; int on = 1; char szService[256]; char *pszService = NULL; struct addrinfo *aiTemp = NULL; g_dwSockErr = 0; //Intialize to no error if(rgService) { pszService = szService; _snprintf(pszService,sizeof(szService)-1, "%d",rgService); } else { got_connected = FALSE; return(got_connected); } strncpy(lpData->szHostName, szHostName,sizeof(lpData->szHostName)); if(getaddrinfo(szHostName, pszService, NULL, &lpData->ai ) != 0 ) { got_connected = FALSE; return(got_connected); } aiTemp = lpData->ai; ui.nottelnet = TRUE; // Assume that it is not a telnet server for starters, later when it is set this flag... to false. ui.honor_localecho = (ui.fDebug & fdwLocalEcho); // Save this and restore after a logon has happned in case of telnet ui.fDebug &= ~fdwLocalEcho; // Clear it. //Continue till connection is successfully established or till the list is exausted while(aiTemp) { if ((lpData->hsd = socket( aiTemp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET) { DEBUG_PRINT(("socket failed \n")); aiTemp = aiTemp->ai_next; continue; } SfuZeroMemory(&myad, sizeof(myad)); //no overflow. Size is constant. myad.ss_family = (u_short)aiTemp->ai_family; if(bind( lpData->hsd, (struct sockaddr *)&myad, sizeof(myad))<0) { DEBUG_PRINT(("bind failed\n")); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; aiTemp = aiTemp->ai_next; continue; } on = 1; { BOOL value_to_set = TRUE; setsockopt( lpData->hsd, SOL_SOCKET, SO_DONTLINGER, ( char * )&value_to_set, sizeof( value_to_set ) ); } if( setsockopt( lpData->hsd, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on) ) < 0) { g_dwSockErr = WSAGetLastError(); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; got_connected = FALSE; DEBUG_PRINT(("setsockopt SO_OOBINLINE failed\n")); DEBUG_PRINT(("FAttemptServerConnect Out\n")); freeaddrinfo(lpData->ai); lpData->ai = NULL; return(got_connected); } else DEBUG_PRINT(("setsockopt SO_OOBINLINE worked\n")); if(SafeSetSocketOptions(lpData->hsd) < 0) { g_dwSockErr = WSAGetLastError(); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; got_connected = FALSE; DEBUG_PRINT(("setsockopt SO_EXCLUSIVEADDRUSE failed\n")); DEBUG_PRINT(("FAttemptServerConnect Out\n")); freeaddrinfo(lpData->ai); lpData->ai = NULL; return(got_connected); } // ================================================================ // MohsinA, 09-Dec-96. if(connect( lpData->hsd, (PVOID)aiTemp->ai_addr,aiTemp->ai_addrlen )<0) { DEBUG_PRINT(("connect failed\n")); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; aiTemp = aiTemp->ai_next; continue; } break; } freeaddrinfo(lpData->ai); lpData->ai = NULL; if(aiTemp == NULL) { DEBUG_PRINT(("FAttemptServerConnect Out\n")); g_dwSockErr = WSAGetLastError(); if(lpData->hsd != INVALID_SOCKET) closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; got_connected = FALSE; return(got_connected); } aiTemp=NULL; // ================================================================ lpData->SessionNumber = 1; if (lpData->SessionNumber != nSessionNone) { DEBUG_PRINT(("sess# <> nsessnone\n")); /* post Async select */ if (WSAAsyncSelect( lpData->hsd, pwi->hwnd, WS_ASYNC_SELECT, (FD_READ | FD_WRITE | FD_CLOSE | FD_OOB)) < 0) { g_dwSockErr = WSAGetLastError(); closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; got_connected = FALSE; lpData->SessionNumber = nSessionNone; DEBUG_PRINT(("WSAAsyncSelect failed\n")); DEBUG_PRINT(("FAttemptServerConnect Out\n")); return(got_connected); } else DEBUG_PRINT(("WSAAsyncSelect worked\n")); got_connected = TRUE; } else DEBUG_PRINT(("sess# <> nsessnone\n")); DEBUG_PRINT(("FAttemptServerConnect Out\n")); return got_connected; } void FCloseConnection(HWND hwnd) { WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI); if(pwi->nd.hsd != INVALID_SOCKET) { closesocket( pwi->nd.hsd ); pwi->nd.hsd = INVALID_SOCKET; } } #endif #ifdef __NOT_USED #define INC(i) (((i)+1 == DATA_BUF_SZ) ? 0 : (i)+1) #define DEC(i) (((i)-1 < 0) ? DATA_BUF_SZ-1 : (i)-1) WORD WGetData(LPNETDATA lpData, LPSTR lpBuffer, WORD cLen) { WORD cb; #ifdef TCPTEST snprintf(DebugBuffer,sizeof(DebugBuffer)-1, "WGetData length %d\n", cLen); OutputDebugString(DebugBuffer); #endif if (lpData->iHead < lpData->iTail) { cb = ( USHORT ) ( (cLen < (lpData->iTail - lpData->iHead - 1)) ? cLen : (lpData->iTail - lpData->iHead - 1) ); memcpy(lpBuffer, &lpData->achData[lpData->iHead+1], cb); //Attack ? size not known. No caller. lpData->iHead = ( USHORT ) ( lpData->iHead + cb ); } else { for(cb=0; (cbiHead) != lpData->iTail); ++cb) { lpData->iHead = ( USHORT ) INC(lpData->iHead); *lpBuffer++ = lpData->achData[lpData->iHead]; } } #ifdef TCPTEST snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "WGetData returning %d bytes (head = %d, tail = %d)\n", cb, lpData->iHead, lpData->iTail ); OutputDebugString(DebugBuffer); #endif return cb; } BOOL FStoreData(LPNETDATA lpData, int max) { BOOL fSuccess = TRUE; WORD tail = lpData->iTail; LPSTR p = lpData->lpReadBuffer; #ifdef TCPTEST snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "FStoreData max %d, (head = %d, tail = %d)\n", max, tail, lpData->iHead ); OutputDebugString(DebugBuffer); #endif if ((max+tail) < DATA_BUF_SZ) { memcpy(&lpData->achData[tail], p, max); //Attack ? Size not known. No caller. tail = ( USHORT ) ( tail + max ); } else { WORD head = lpData->iHead; int i; for (i=0; iachData[tail] = *p++; tail = ( USHORT ) INC(tail); } } } lpData->iTail = tail; #ifdef TCPTEST snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "FStoreData returning %d\n", fSuccess ); OutputDebugString(DebugBuffer); #endif return fSuccess; } #endif void CALLBACK NBReceiveData(PVOID pncb) { } /* following four routines modified from VTP's routines. */ BOOL FTelXferStart(WI *pwi, int nSessionNumber) { #ifdef TELXFER unsigned short u; char rgchFileOrig[OFS_MAXPATHNAME]; char rgchFile[OFS_MAXPATHNAME]; xfGetData(0, (char *)&u, 2, nSessionNumber); // Mode SfuZeroMemory(&pwi->svi, sizeof(SVI)); //no overflow. Size is constant pwi->svi.hfile = INVALID_HANDLE_VALUE; pwi->svi.lExit = -1; pwi->svi.lCleanup = -1; if (u != 0) // For now must be zero return FALSE; pwi->trm.fHideCursor = TRUE; xfGetData(1, (char *)&u, 2, nSessionNumber); // Length of name xfGetData(2, rgchFileOrig, u, nSessionNumber); // Name xfGetData(3, (char *)&pwi->svi.cbFile, 4, nSessionNumber); // Filesize lstrcpyn(rgchFile, rgchFileOrig, OFS_MAXPATHNAME -1); /* If the user doesn't have the shift key down, prompt for */ /* a directory and name for the file */ if (!(ui.fPrompt & fdwSuppressDestDirPrompt) && (GetAsyncKeyState(VK_SHIFT) >= 0)) { if ( !FGetFileName(hwnd, rgchFile, NULL) ) { goto err; } } pwi->svi.hfile = CreateFile(rgchFile, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (pwi->svi.hfile == INVALID_HANDLE_VALUE) { ErrorMessage(szCantOpenFile, szAppName); goto err; } pwi->svi.puchBuffer = LocalAlloc(LPTR, SV_DATABUF); if (pwi->svi.puchBuffer == NULL) { ErrorMessage(szOOM, szAppName); goto err; } pwi->svi.nSessionNumber = nSessionNumber; pwi->svi.hthread = CreateThread(NULL, 0, SVReceive, &pwi->svi, CREATE_SUSPENDED, &pwi->svi.dwThreadId); if (pwi->svi.hthread == NULL) { ErrorMessage(szNoThread, szAppName); goto err; } // Skip 4 which is ^D xfPutc(5, nSessionNumber); // Get file _snwprintf(rgchFile, OFS_MAXPATHNAME -1, szBannerMessage, rgchFileOrig, pwi->svi.cbFile); DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(rgchFile), rgchFile); DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(szInitialProgress), szInitialProgress); /* In case the screen just scrolled up, paint the window */ UpdateWindow( hwnd ); ResumeThread( pwi->svi.hthread ); return TRUE; err: if ( pwi ) { if (pwi->svi.puchBuffer != NULL) LocalFree( (HANDLE)pwi->svi.puchBuffer ); if (pwi->svi.hfile != INVALID_HANDLE_VALUE) CloseHandle( pwi->svi.hfile ); SfuZeroMemory(&pwi->svi, sizeof(SVI)); //no overflow. size is constant. pwi->svi.hfile = INVALID_HANDLE_VALUE; pwi->svi.lExit = -1; pwi->svi.lCleanup = -1; } pwi->trm.fHideCursor = FALSE; return FALSE; #else return TRUE; #endif } BOOL FTelXferEnd(WI *pwi, DWORD dwWhy) { #ifdef TELXFER DWORD dwStatus = NO_ERROR; BOOL fTransferOK = FALSE; BOOL fAbortDownload = FALSE; BOOL fCleanup = FALSE; LPNETDATA lpData = &pwi->nd; SVI *psvi = &pwi->svi; MSG msg; switch ( dwWhy ) { case SV_DISCONNECT: case SV_HANGUP: case SV_QUIT: if (InterlockedIncrement(&psvi->lExit) == 0) { if (psvi->hthread != NULL) { (void)GetExitCodeThread(psvi->hthread, &dwStatus); if (dwStatus == STILL_ACTIVE) { if (MessageBox(hwnd, szAbortDownload, szAppName, MB_DEFBUTTON2 | MB_YESNO | MB_ICONEXCLAMATION) == IDYES) { fAbortDownload = fCleanup = TRUE; } /* See if the thread has finished yet */ GetExitCodeThread(psvi->hthread, &dwStatus); if ( fAbortDownload ) { /* If the thread hasn't finished yet, tell it to stop */ if (dwStatus == STILL_ACTIVE) { HCURSOR hcursorOld; hcursorOld = SetCursor( LoadCursor(NULL, IDC_WAIT)); psvi->dwCommand = 1; WaitForSingleObject(psvi->hthread, INFINITE); GetExitCodeThread(psvi->hthread, &dwStatus); (void)SetCursor( hcursorOld ); } /* "Eat" any progress messages that might be around */ while (PeekMessage(&msg, hwnd, SV_PROGRESS, SV_DONE, PM_REMOVE)) { if (msg.message == SV_PROGRESS) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } } else if (dwStatus != STILL_ACTIVE) { fCleanup = TRUE; } } else { fAbortDownload = fCleanup = TRUE; } /* If we've stopped the download, then close the thread */ if ( fCleanup ) { CloseHandle( psvi->hthread ); psvi->hthread = NULL; if (lpData->SessionNumber != nSessionNone) { xfPutc((char)(!fTransferOK ? 0x7F : 0x06), lpData->SessionNumber); if ( !fAbortDownload ) (void)FPostReceive( lpData ); } } if (dwStatus == NO_ERROR) fTransferOK = TRUE; } InterlockedDecrement( &psvi->lExit ); /* If the thread wasn't aborted and it hasn't finished, return */ if (!fAbortDownload && !fCleanup) return fAbortDownload; } else { InterlockedDecrement( &psvi->lExit ); break; } case SV_DONE: if (dwWhy == SV_DONE) { fAbortDownload = fCleanup = TRUE; } /* If we're the only thread in the function, close everything down */ if (InterlockedIncrement(&psvi->lExit) == 0) { if (psvi->hthread != NULL) { WaitForSingleObject(psvi->hthread, INFINITE); GetExitCodeThread(psvi->hthread, &dwStatus); CloseHandle( psvi->hthread ); psvi->hthread = NULL; if (dwStatus == NO_ERROR) fTransferOK = TRUE; } } /* Do cleanup of struct only once */ if ((InterlockedIncrement(&psvi->lCleanup) == 0) && (psvi->puchBuffer != NULL)) { LocalFree( (HANDLE)psvi->puchBuffer ); psvi->puchBuffer = NULL; if (psvi->hfile != INVALID_HANDLE_VALUE) { CloseHandle( psvi->hfile ); psvi->hfile = INVALID_HANDLE_VALUE; } psvi->cbFile = 0; psvi->cbReadTotal = 0; psvi->dwCommand = 0; psvi->dwThreadId = 0; psvi->nSessionNumber = nSessionNone; if ((dwStatus == NO_ERROR) || (dwStatus == ERROR_OPERATION_ABORTED)) { lstrcpyn(pchNBBuffer, szSendTelEnd,sizeof(pchNBBuffer)-1); } else { _snwprintf(pchNBBuffer,sizeof(pchNBBuffer)-1,szSendTelError, dwStatus); } DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(pchNBBuffer), pchNBBuffer); pwi->ichTelXfer = 0; pwi->trm.fHideCursor = FALSE; } InterlockedDecrement( &psvi->lCleanup ); if ((dwWhy == SV_DONE) && (lpData->SessionNumber != nSessionNone)) { xfPutc((char)(!fTransferOK ? 0x7F : 0x06), lpData->SessionNumber); (void)FPostReceive( lpData ); } InterlockedDecrement( &psvi->lExit ); break; default: break; } return fAbortDownload; #else return TRUE; #endif } #ifdef TELXFER static void xfGetData(char c, char *pchBuffer, DWORD cbBuffer, int nSessionNumber) { DWORD cbRead; xfPutc(c, nSessionNumber); while ( cbBuffer ) { cbRead = xfGetSomeData(pchBuffer, cbBuffer, nSessionNumber); if (cbRead == 0) break; cbBuffer -= cbRead; pchBuffer += cbRead; } } #endif #ifdef USETCP #ifdef TELXFER static DWORD xfGetSomeData(char *pchBuffer, DWORD cbBuffer, int nSessionNumber) { return 1; } #endif //TELXFER #ifdef TELXFER static void xfPutc(char c, int nSessionNumber) { } #endif #endif #ifdef TELXFER BOOL FGetFileName(HWND hwndOwner, char *rgchFile, char *rgchTitle) { OPENFILENAME ofn; /* Fill in struct. */ ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndOwner; ofn.hInstance = NULL; ofn.lpstrFilter = (LPSTR) szAllFiles; ofn.lpstrCustomFilter = (LPSTR) NULL; ofn.nMaxCustFilter = 0; ofn.nFilterIndex = 0; ofn.lpstrFile = (LPSTR) rgchFile; ofn.nMaxFile = OFS_MAXPATHNAME; ofn.lpstrFileTitle = (LPSTR) rgchTitle; ofn.nMaxFileTitle = OFS_MAXPATHNAME; ofn.lpstrInitialDir = (LPSTR) 0; ofn.lpstrTitle = (LPSTR) szDownloadAs; ofn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = (LPSTR) NULL; ofn.lCustData = 0; ofn.lpfnHook = NULL; ofn.lpTemplateName = NULL; if ( !GetSaveFileName(&ofn) ) { return FALSE; } return TRUE; } #endif DWORD WINAPI SVReceive(SVI *psvi) { DWORD dwReturn = NO_ERROR; #ifdef TELXFER if ( psvi ) { while ((psvi->cbFile > 0) && (psvi->dwCommand == 0)) { DWORD cbSomeData; DWORD cbRead; cbRead = 0; while ((psvi->cbFile > 0) && (cbRead < 1024)) { cbSomeData = xfGetSomeData(psvi->puchBuffer+cbRead, (unsigned short) 0x4000 - cbRead, psvi->nSessionNumber); if (cbSomeData > psvi->cbFile) cbSomeData = psvi->cbFile; psvi->cbFile -= cbSomeData; cbRead += cbSomeData; } if (!WriteFile(psvi->hfile, psvi->puchBuffer, cbRead, &cbSomeData, NULL)) { dwReturn = GetLastError(); break; } psvi->cbReadTotal += cbRead; PostMessage(hwndMain, SV_PROGRESS, 0, psvi->cbReadTotal); } /* caller must've signaled and waited for thread to stop */ if ((dwReturn == NO_ERROR) && (psvi->dwCommand != 0) && (psvi->cbFile > 0)) { dwReturn = ERROR_OPERATION_ABORTED; } else if ((psvi->dwCommand == 0) || (psvi->cbFile == 0)) { /* If thread stopped by itself, need to tell caller to kill it * BUT ONLY if the main thread isn't tying to kill off this * thread. */ if (InterlockedIncrement(&psvi->lExit) == 0) PostMessage(hwndMain, SV_END, 0, 0L); InterlockedDecrement( &psvi->lExit ); } } else if (psvi->lExit < 0) { /* If thread stopped by itself, need to tell caller to kill it */ PostMessage(hwndMain, SV_END, 0, 0L); } #endif return dwReturn; } #ifdef USETCP BOOL FHangupConnection(WI *pwi, LPNETDATA lpData) { if (lpData->SessionNumber != nSessionNone) { if(lpData->hsd != INVALID_SOCKET) { closesocket( lpData->hsd ); lpData->hsd = INVALID_SOCKET; } lpData->SessionNumber = nSessionNone; } return FALSE; } #endif