/*++ Copyright (C) Microsoft Corporation, 1993 - 1999 Module Name: Remote.c Abstract: This module contains the main() entry point for Remote. Calls the Server or the Client depending on the first parameter. Author: Rajivendra Nath (rajnath) 2-Jan-1993 Environment: Console App. User mode. Revision History: --*/ #include #include #include "Remote.h" TCHAR HostName[HOSTNAMELEN]; TCHAR * ChildCmd; TCHAR* PipeName; TCHAR* ServerName; TCHAR* Username; TCHAR* Password; HANDLE MyOutHandle; BOOL bIPLocked=FALSE; BOOL IsAdvertise=TRUE; DWORD ClientToServerFlag; TCHAR* ColorList[]={ TEXT("black"), TEXT("blue"), TEXT("green"), TEXT("cyan"), TEXT("red"), TEXT("purple"), TEXT("yellow"), TEXT("white"), TEXT("lblack"), TEXT("lblue"), TEXT("lgreen"), TEXT("lcyan"), TEXT("lred"), TEXT("lpurple"), TEXT("lyellow"), TEXT("lwhite") }; WORD GetColorNum( TCHAR* color ); VOID SetColor( WORD attr ); BOOL GetNextConnectInfo( TCHAR** SrvName, TCHAR** PipeName ); CONSOLE_SCREEN_BUFFER_INFO csbiOriginal; int _cdecl _tmain(int argc, TCHAR *argv[]) { WORD RunType; // Server or Client end of Remote DWORD len=HOSTNAMELEN-1; int i, FirstArg; BOOL bSetAttrib=FALSE; // Change Console Attributes BOOL bPromptForArgs=FALSE; // Is /P option BOOL bIPSession=TRUE; // Is /N for Named Pipes TCHAR szTitle[100]; // New Title TCHAR orgTitle[100]; // Old Title WORD wAttrib; // Console Attributes GetComputerName((LPTSTR)HostName,&len); MyOutHandle=GetStdHandle(STD_OUTPUT_HANDLE); // // Save Existing Values // // //Colors /f /b // // //Title /T Title // if (GetConsoleScreenBufferInfo(MyOutHandle,&csbiOriginal)) { wAttrib = csbiOriginal.wAttributes; if (!GetConsoleTitle(orgTitle,sizeof(orgTitle)/sizeof(orgTitle[0]))) { orgTitle[0] = 0; } } else { // // either stdout is a pipe, or it wasn't opened for // GENERIC_READ along with GENERIC_WRITE, in which // case our color manipulations will work so we need // to pick default colors. // wAttrib = FOREGROUND_GREEN | FOREGROUND_INTENSITY; orgTitle[0] = 0; } // // Parameter Processing // // For Server: // Remote /S [Optional Params] // // For Client: // Remote /C [Optional Params] // or // Remote /P // This will loop continously prompting for different // Servers and Pipename if ((argc<2)||((argv[1][0]!='/')&&(argv[1][0]!='-'))) { DisplayServerHlp(); DisplayClientHlp(); return(1); } switch(argv[1][1]) { case 'c': case 'C': // // Is Client End of Remote // if ((argc<4)||((argv[1][0]!='/')&&(argv[1][0]!='-'))) { DisplayServerHlp(); DisplayClientHlp(); return(1); } ServerName=argv[2]; PipeName=argv[3]; FirstArg=4; RunType=REMOTE_CLIENT; break; case 'p': case 'P': // // Is Client End of Remote // bPromptForArgs=TRUE; RunType=REMOTE_CLIENT; FirstArg=2; break; case 's': case 'S': // // Is Server End of Remote // if ((argc<4)||((argv[1][0]!='/')&&(argv[1][0]!='-'))) { DisplayServerHlp(); DisplayClientHlp(); return(1); } ChildCmd=argv[2]; PipeName=argv[3]; FirstArg=4; RunType=REMOTE_SERVER; break; default: DisplayServerHlp(); DisplayClientHlp(); return(1); } if (RunType==REMOTE_SERVER) { // // Base Name of Executable // For setting the title // TCHAR *tcmd=ChildCmd; while ((*tcmd!=' ') &&(*tcmd!=0)) tcmd++; while ((tcmd!=ChildCmd)&&(*tcmd!='\\'))tcmd--; _stprintf( szTitle, TEXT("%-8.8s [WSRemote /C %s %s]"), tcmd, HostName, PipeName); } // //Process Common (Optional) Parameters // for (i=FirstArg;i=argc) { _tprintf( TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]); break; } Username=(argv[i]); break; case 'p': // Only Valid for Server End case 'P': // Password To Use to Connect to Session i++; if (i>=argc) { _tprintf( TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]); break; } Password=(argv[i]); break; case 'l': // Only Valid for client End case 'L': // Max Number of Lines to recieve from Server i++; if (i>=argc) { _tprintf(TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]); break; } LinesToSend=(DWORD)_ttoi(argv[i])+1; break; case 't': // Title to be set instead of the default case 'T': i++; if (i>=argc) { _tprintf(TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]); break; } _stprintf( szTitle, TEXT("%s"),argv[i]); break; case 'b': // Background color case 'B': i++; if (i>=argc) { _tprintf(TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]); break; } { WORD col=GetColorNum(argv[i]); if (col!=0xffff) { bSetAttrib=TRUE; wAttrib=col<<4|(wAttrib&0x000f); } break; } case 'f': // Foreground color case 'F': i++; if (i>=argc) { _tprintf(TEXT("Incomplete Param %s..Ignoring\n"),argv[i-1]); break; } { WORD col=GetColorNum(argv[i]); if (col!=0xffff) { bSetAttrib=TRUE; wAttrib=col|(wAttrib&0x00f0); } break; } case 'q': case 'Q': IsAdvertise=FALSE; ClientToServerFlag|=0x80000000; break; case 'n': case 'N': bIPSession=FALSE; break; case 'i': case 'I': bIPLocked=TRUE; break; default: _tprintf(TEXT("Unknown Parameter=%s %s\n"),argv[i-1],argv[i]); break; } } // //Now Set various Parameters // // //Colors // SetColor(wAttrib); if (RunType==REMOTE_CLIENT) { BOOL done=FALSE; // // Set Client end defaults and start client // while(!done) { if (!bPromptForArgs || GetNextConnectInfo(&ServerName,&PipeName) ) { _stprintf( szTitle, TEXT("WSRemote /C %s %s"),ServerName,PipeName); SetConsoleTitle(szTitle); if (!bIPSession) { // // Start Client (Client.C) // Client(ServerName,PipeName); } else { SockClient(ServerName,PipeName); } } done=!bPromptForArgs; } } if (RunType==REMOTE_SERVER) { SetConsoleTitle(szTitle); // // Start Server (Server.C) // Server(ChildCmd,PipeName); } // //Reset Colors // SetColor(csbiOriginal.wAttributes); if (orgTitle[0]) { SetConsoleTitle(orgTitle); } ExitProcess(0); return( 1 ); } /*************************************************************/ VOID ErrorExit( TCHAR* str ) { _tprintf(TEXT("Error-%d:%s\n"),GetLastError(),str); ExitProcess(1); } /*************************************************************/ DWORD ReadFixBytes( HANDLE hRead, TCHAR* Buffer, DWORD ToRead, DWORD TimeOut //ignore for timebeing ) { DWORD xyzBytesRead=0; DWORD xyzBytesToRead=ToRead; TCHAR* xyzbuff=Buffer; while(xyzBytesToRead!=0) { if (!ReadFile(hRead,xyzbuff,xyzBytesToRead,&xyzBytesRead,NULL)) { return(xyzBytesToRead); } xyzBytesToRead-=xyzBytesRead; xyzbuff+=xyzBytesRead; } return(0); } /*************************************************************/ /*************************************************************/ DWORD SockReadFixBytes( SOCKET hSocket, TCHAR* Buffer, DWORD ToRead, DWORD TimeOut //ignore for timebeing ) { DWORD xyzBytesRead=0; DWORD xyzBytesToRead=ToRead; TCHAR* xyzbuff=Buffer; while(xyzBytesToRead!=0) { if (!ReadSocket(hSocket,xyzbuff,xyzBytesToRead,&xyzBytesRead)) { return(xyzBytesToRead); } xyzBytesToRead-=xyzBytesRead; xyzbuff+=xyzBytesRead; } return(0); } /*************************************************************/ VOID DisplayClientHlp() { _tprintf(TEXT("\n To Start the CLIENT end of WSREMOTE\n")); _tprintf(TEXT(" ---------------------------------\n")); _tprintf(TEXT(" Syntax : WSREMOTE /C [Param]\n")); _tprintf(TEXT(" Example: WSREMOTE /C iisdebug 70\n")); _tprintf(TEXT(" This would connect to a server session on \n")); _tprintf(TEXT(" iisdebug with id \"70\" if there was a\n")); _tprintf(TEXT(" WSREMOTE /S <\"Cmd\"> 70\n")); _tprintf(TEXT(" started on the machine iisdebug.\n\n")); _tprintf(TEXT(" To Exit: %cQ (Leaves the Remote Server Running)\n"),COMMANDCHAR); _tprintf(TEXT(" [Param]: /L <# of Lines to Get>\n")); _tprintf(TEXT(" [Param]: /F \n")); _tprintf(TEXT(" [Param]: /B \n")); _tprintf(TEXT(" [Param]: /N (Connect over Named Pipes)\n")); _tprintf(TEXT(" [Param]: /U (Username to connect)\n")); _tprintf(TEXT(" [Param]: /P (Password to connect)\n")); _tprintf(TEXT("\n")); } /*************************************************************/ VOID DisplayServerHlp() { #define WRITEF2(VArgs) { \ HANDLE xh=GetStdHandle(STD_OUTPUT_HANDLE); \ TCHAR VBuff[256]; \ DWORD tmp; \ _stprintf VArgs; \ WriteFile(xh,VBuff,lstrlen(VBuff),&tmp,NULL); \ } \ _tprintf(TEXT("\n To Start the SERVER end of WSREMOTE\n")); _tprintf(TEXT(" ---------------------------------\n")); _tprintf(TEXT(" Syntax : WSREMOTE /S <\"Cmd\"> [Param]\n")); _tprintf(TEXT(" Syntax : WSREMOTE /S <\"Cmd\"> [Param]\n")); _tprintf(TEXT(" Example: WSREMOTE /S \"cmd.exe\" inetinfo\n")); _tprintf(TEXT(" To interact with this \"Cmd\" \n")); _tprintf(TEXT(" from some other machine\n")); _tprintf(TEXT(" - start the client end by:\n")); _tprintf(TEXT(" REMOTE /C %s PortNum\n\n"),HostName); _tprintf(TEXT(" To Exit: %cK \n"),COMMANDCHAR); _tprintf(TEXT(" [Param]: /F \n")); _tprintf(TEXT(" [Param]: /B \n")); _tprintf(TEXT(" [Param]: /I (Turns ON IP Blocking)\n")); _tprintf(TEXT(" [Param]: /U (Username to connect)\n")); _tprintf(TEXT(" [Param]: /P (Password to connect)\n")); _tprintf(TEXT("\n")); } WORD GetColorNum( TCHAR *color ) { WORD wIndex; _tcslwr(color); for (wIndex=0;wIndex<16;wIndex++) { if (_tcscmp(ColorList[wIndex],color)==0) { return(wIndex); } } return ((WORD)_ttoi(color)); } VOID SetColor( WORD attr ) { COORD origin={0,0}; DWORD dwrite; FillConsoleOutputAttribute ( MyOutHandle,attr,csbiOriginal.dwSize. X*csbiOriginal.dwSize.Y,origin,&dwrite ); SetConsoleTextAttribute(MyOutHandle,attr); } BOOL GetNextConnectInfo( TCHAR** SrvName, TCHAR** PipeName ) { static TCHAR szServerName[64]; static TCHAR szPipeName[32]; TCHAR *s; int StringLen; __try { ZeroMemory(szServerName,64); ZeroMemory(szPipeName,32); SetConsoleTitle( TEXT("Remote - Prompting for next Connection")); _tprintf(TEXT("Debugger machine (server): ")); fflush(stdout); if (!fgets(szServerName, sizeof(szServerName), stdin)) { return FALSE; } StringLen = strlen(szServerName); if (!StringLen || (!feof(stdin) && szServerName[StringLen-1] != '\n')) { return FALSE; } if (szServerName[StringLen-1] == '\n') { if (StringLen == 1) { return (FALSE); } szServerName[StringLen-1] = '\0'; } if (szServerName[0] == COMMANDCHAR && (szServerName[1] == 'q' || szServerName[1] == 'Q') ) { return(FALSE); } if (s = _tcschr( szServerName, ' ' )) { *s++ = '\0'; while (*s == ' ') { s += 1; } *PipeName=_tcscpy(szPipeName, s); _tprintf(szPipeName); fflush(stdout); } if (_tcslen(szPipeName) == 0) { _tprintf(TEXT("Debuggee machine : ")); fflush(stdout); if (!fgets(szPipeName, sizeof(szPipeName), stdin)) { return FALSE; } StringLen = strlen(szPipeName); if (!StringLen || (!feof(stdin) && szPipeName[StringLen-1] != '\n')) { return FALSE; } if (szPipeName[StringLen-1] == '\n') { szPipeName[StringLen-1] = '\0'; } } if (s = _tcschr(szPipeName, ' ')) { *s++ = '\0'; } if (szPipeName[0] == COMMANDCHAR && (szPipeName[1] == 'q' || szPipeName[1] == 'Q') ) { return(FALSE); } _tprintf(TEXT("\n\n")); } __except(EXCEPTION_EXECUTE_HANDLER) { return(FALSE); // Ignore exceptions } return(TRUE); } /*************************************************************/ VOID Errormsg( TCHAR* str ) { _tprintf(TEXT("Error (%d) - %s\n"),GetLastError(),str); } /*************************************************************/ BOOL ReadSocket(SOCKET s,TCHAR * buff,int len,DWORD* dread) { BOOL bRet = FALSE; DWORD numread; #ifdef UNICODE char * pszAnsiStr = (char *)calloc( (len + 1), sizeof(char) ); if (pszAnsiStr) { int nErr; numread = (DWORD)recv( s, pszAnsiStr, len, 0); if (SOCKET_ERROR != numread) { nErr = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszAnsiStr, len, buff, len ); if (nErr) { *dread = numread; bRet = TRUE; } //Base64Decode(buff,DecodeBuffer); } free( pszAnsiStr ); } #else numread = (DWORD)recv( s, buff, len, 0); if (SOCKET_ERROR != numread) { *dread = numread; bRet = TRUE; } #endif return bRet; } // returns TRUE if successful, false otherwise BOOL WriteSocket( SOCKET s, TCHAR * buff, int len, DWORD* dsent) { BOOL bRet = FALSE; DWORD numsent; #ifdef UNICODE int nStrLen = lstrlen( buff ); if (nStrLen) { char * pszAnsiStr = (char *)malloc( nStrLen + 1 ); if (pszAnsiStr) { int nErr = WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, buff, nStrLen, pszAnsiStr, nStrLen, NULL, NULL ); if (nErr) { numsent = (DWORD)send(s, pszAnsiStr, nStrLen, 0); if (SOCKET_ERROR != numsent) { *dsent = numsent; bRet = TRUE; } } //Base64Decode(buff,DecodeBuffer); free( pszAnsiStr ); } } #else numsent = (DWORD)send(s, buff, len, 0); if (SOCKET_ERROR != numsent) { *dsent = numsent; bRet = TRUE; } #endif return bRet; } #ifdef UNICODE // returns TRUE if successful, false otherwise BOOL WriteSocketA( SOCKET s, char * pszAnsiStr, int len, DWORD * dsent) { BOOL bRet = FALSE; DWORD numsent; numsent = (DWORD)send(s, pszAnsiStr, len, 0); if (SOCKET_ERROR != numsent) { *dsent = numsent; bRet = TRUE; } //Base64Decode(buff,DecodeBuffer); return bRet; } #endif //////////////////////////////////////////////// unsigned char Base64Table[64] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'}; VOID Base64Encode( TCHAR * String, DWORD StringLength, TCHAR * EncodeBuffer) { DWORD EncodeDword; int Index; memset(EncodeBuffer, 0, 2 * StringLength); Index = 0; while (StringLength >= 3) { // // Encode a three byte chunk // EncodeDword = (String[0] << 16) & 0xff0000; EncodeDword += (String[1] << 8) & 0xff00; EncodeDword += String[2] & 0xff; EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 18) & 63]; EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 12) & 63]; EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 6) & 63]; EncodeBuffer[Index++] = Base64Table[EncodeDword & 63]; String += 3; StringLength -= 3; } switch (StringLength) { case 1: EncodeDword = (String[0] << 16) & 0xff0000; EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 18) & 63]; EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 12) & 63]; EncodeBuffer[Index++] = '='; EncodeBuffer[Index++] = '='; break; case 2: EncodeDword = (String[0] << 16) & 0xff0000; EncodeDword += (String[1] << 8) & 0xff00; EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 18) & 63]; EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 12) & 63]; EncodeBuffer[Index++] = Base64Table[(EncodeDword >> 6) & 63]; EncodeBuffer[Index++] = '='; break; } EncodeBuffer[Index] = 0; return; } int GetBase64Index( TCHAR A) { int i; for (i=0; i<64; i++) { if (Base64Table[i] == A) { return i; } } return -1; } VOID Base64Decode( TCHAR * String, TCHAR * DecodeBuffer) { DWORD DecodeDword; int Index = 0; memset(DecodeBuffer, 0, _tcslen(String)); if (_tcslen(String) % 4) { printf("WCAT INTERNAL ERROR %s %d\n", __FILE__, __LINE__); return; } while (*String) { // // Decode a four byte chunk // if (GetBase64Index(String[0]) < 0) { // // Invalid string // printf("WCAT INTERNAL ERROR %s %d\n", __FILE__, __LINE__); return; } DecodeDword = ((unsigned int) GetBase64Index(String[0])) << 18; if (GetBase64Index(String[1]) >= 0) { // // still more characters // DecodeDword += ((unsigned int) GetBase64Index(String[1])) << 12; if (GetBase64Index(String[2]) >= 0) { // // still more characters // DecodeDword += ((unsigned int) GetBase64Index(String[2])) << 6; if (GetBase64Index(String[3]) >= 0) { // // still more characters // DecodeDword += (unsigned int) GetBase64Index(String[3]); DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 16) & 0xff); DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 8) & 0xff); DecodeBuffer[Index++] = (unsigned char) (DecodeDword & 0xff); } else { DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 16) & 0xff); DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 8) & 0xff); } } else { DecodeBuffer[Index++] = (unsigned char) ((DecodeDword >> 16) & 0xff); } } String += 4; } return; } VOID SplitUserName( TCHAR * FullName, TCHAR * Domain, TCHAR * UserName) { TCHAR * Slash; Slash = _tcsstr(FullName, TEXT(":")); if (Slash) { // there is a domain name *Slash = 0; _tcscpy(Domain, FullName); _tcscpy(UserName, Slash+1); *Slash = ':'; } else { *Domain = 0; _tcscpy(UserName, FullName); } } #ifdef UNICODE // caller must free buffer WCHAR * inet_ntoaw( struct in_addr stInet ) { char * pszAnsiInetStr = inet_ntoa( stInet ); int nStrLen = strlen( pszAnsiInetStr ); WCHAR * pszInetStr = (WCHAR *)calloc( (nStrLen + 1), sizeof( TCHAR )); int nErr = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszAnsiInetStr, nStrLen, pszInetStr, nStrLen ); if (!nErr) { free( pszInetStr ); pszInetStr = NULL; } return pszInetStr; } BOOL ReadFileW( HANDLE hFile, // handle of file to read WCHAR * pszBuffer, // pointer to buffer that receives data DWORD dwLength, // number of bytes to read LPDWORD pdwRead, // pointer to number of bytes read LPOVERLAPPED pData // pointer to structure for data ) { BOOL bRet = FALSE; char * pszAnsi = (char *)calloc( dwLength + 1, sizeof(char *)); if (pszAnsi) { bRet = ReadFile( hFile, pszAnsi, dwLength, pdwRead, pData); if (bRet) { int nErr = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pszAnsi, *pdwRead, pszBuffer, *pdwRead ); if (!nErr) { bRet = FALSE; } } free( pszAnsi ); } return bRet; } BOOL WriteFileW( HANDLE hFile, // handle to file to write to WCHAR * pszBuffer, // pointer to data to write to file DWORD dwWrite, // number of bytes to write LPDWORD pdwWritten, // pointer to number of bytes written LPOVERLAPPED pData // pointer to structure for overlapped I/O ) { BOOL bRet = FALSE; int nStrLen = lstrlen( pszBuffer ); if (nStrLen) { char * pszAnsiStr = (char *)malloc( nStrLen + 1 ); if (pszAnsiStr) { int nErr = WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, pszBuffer, nStrLen, pszAnsiStr, nStrLen, NULL, NULL ); if (nErr) { bRet = WriteFile( hFile, pszAnsiStr, dwWrite, pdwWritten, pData); } free( pszAnsiStr ); } } return bRet; } // caller most free buffer BOOL GetAnsiStr( WCHAR * pszWideStr, char * pszAnsiStr, UINT uBufSize ) { BOOL bRet = FALSE; if (pszWideStr && pszAnsiStr) { int nStrLen = lstrlen( pszWideStr ); if (nStrLen) { int nErr = WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK, pszWideStr, nStrLen, pszAnsiStr, uBufSize - 1, NULL, NULL ); if (nErr) { pszAnsiStr[nStrLen] = '\0'; bRet = TRUE; } } } return bRet; } #endif