Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2033 lines
60 KiB

  1. //Copyright (c) Microsoft Corporation. All rights reserved.
  2. /****************************************************************************
  3. FILE: NetIO.c
  4. Functions for connecting to machines and handling data transfers
  5. between machines.
  6. TABS:
  7. Set for 4 spaces.
  8. ****************************************************************************/
  9. #include <stdio.h>
  10. #include <windows.h> // required for all Windows applications
  11. #include <lmcons.h>
  12. #include <tchar.h>
  13. #pragma warning (disable: 4201) // disable "nonstandard extension used : nameless struct/union"
  14. #include <commdlg.h>
  15. #pragma warning (default: 4201)
  16. #include <stdlib.h>
  17. #include "WinTel.h" // specific to this program
  18. #include "commands.h"
  19. #include "debug.h"
  20. #pragma warning( disable : 4100 )
  21. #ifdef USETCP
  22. #include "telnet.h"
  23. #endif
  24. char *rgchTermType[] = { "ANSI", "VT100", "VT52", "VTNT" };
  25. extern void NTLMCleanup();
  26. extern BOOL DoNTLMAuth(WI *pwi, PUCHAR pBuffer, DWORD dwSize);
  27. extern int SafeSetSocketOptions(SOCKET s);
  28. BOOL g_fSentWillNaws = FALSE;
  29. static BOOL FAttemptServerConnect(WI *pwi, LPSTR, LPNETDATA);
  30. static void xfGetData(char, char *, DWORD, int);
  31. #ifdef USETCP
  32. #ifdef TELXFER
  33. static DWORD xfGetSomeData(char *, DWORD, int);
  34. #endif //TELXFER
  35. #endif //USETCP
  36. static void xfPutc(char, int);
  37. static int term_inx = 0;
  38. extern BOOL StartNTLMAuth(WI *);
  39. extern TCHAR szUserName[ UNLEN + 1 ];
  40. extern CHAR* szUser;
  41. TCHAR szCombinedFailMsg [255];
  42. extern HANDLE g_hControlHandlerEvent;
  43. extern HANDLE g_hCaptureConsoleEvent;
  44. extern HANDLE g_hAsyncGetHostByNameEvent;
  45. extern HANDLE g_hRemoteNEscapeModeDataSync;
  46. extern BOOL g_fConnectFailed;
  47. void
  48. GetErrMsgString( DWORD dwErrNum, LPTSTR *lpBuffer )
  49. {
  50. DWORD dwStatus = 0;
  51. LCID old_thread_locale;
  52. switch (GetACP())
  53. {
  54. // for Hebrew and arabic winerror.h is not localized..so get the english one for all these
  55. case 1256:
  56. case 1255:
  57. old_thread_locale = GetThreadLocale();
  58. SetThreadLocale(
  59. MAKELCID(
  60. MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
  61. SORT_DEFAULT
  62. )
  63. );
  64. break;
  65. default:
  66. old_thread_locale = -1;
  67. }
  68. dwStatus = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  69. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  70. NULL, dwErrNum, LANG_NEUTRAL, ( LPTSTR )lpBuffer, 0, NULL );
  71. if( !dwStatus )
  72. {
  73. *lpBuffer = NULL;
  74. }
  75. if (old_thread_locale != -1)
  76. {
  77. SetThreadLocale(old_thread_locale);
  78. }
  79. return;
  80. }
  81. BOOL
  82. FConnectToServer(WI *pwi, LPSTR szHostName, LPNETDATA lpData)
  83. {
  84. BOOL fResult;
  85. // Before we Connect we make sure we are not connected.
  86. // This ASSERT should never blowup !!
  87. ASSERT(fConnected==FALSE);
  88. // We initialize stuff for this connection.
  89. pwi->trm.SentTermType = TT_UNKNOWN;
  90. pwi->trm.CurrentTermType = TT_ANSI; /* this is our default term type*/
  91. fResult = FAttemptServerConnect(pwi, szHostName, lpData);
  92. if( fResult != TRUE )
  93. {
  94. TCHAR szStr[ cchMaxHostName ];
  95. g_fConnectFailed = TRUE;
  96. if( g_szPortNameOrNo[ 0 ] == 0 )
  97. {
  98. _sntprintf( g_szPortNameOrNo,cchMaxHostName-1,( LPCTSTR )L"%d", rgService );
  99. }
  100. _sntprintf( szStr, cchMaxHostName -1 ,szOnPort, g_szPortNameOrNo );
  101. _sntprintf(szCombinedFailMsg,ARRAY_SIZE(szCombinedFailMsg)-1,_T("%s%s"),szConnectFailedMsg,szStr);
  102. g_szPortNameOrNo[ 0 ] = 0;
  103. if( g_dwSockErr == 0 )
  104. {
  105. //Not an error we want to inform abt
  106. ErrorMessage( szCombinedFailMsg, szConnectFailed );
  107. }
  108. else
  109. {
  110. DWORD dwWritten = 0;
  111. LPTSTR lpBuffer = NULL;
  112. GetErrMsgString( g_dwSockErr, &lpBuffer );
  113. if( lpBuffer )
  114. {
  115. ConnectTimeErrorMessage( szCombinedFailMsg, lpBuffer );
  116. LocalFree( lpBuffer );
  117. }
  118. else
  119. {
  120. ErrorMessage( szCombinedFailMsg, szConnectFailed );
  121. }
  122. }
  123. }
  124. return fResult;
  125. }
  126. #ifdef USETCP
  127. /*** FPostReceive - post an asynchronous receive
  128. */
  129. BOOL
  130. FPostReceive(LPNETDATA lpData)
  131. {
  132. #ifdef NBTEST
  133. OutputDebugString("PostReceive In\n");
  134. #endif
  135. #ifdef NBTEST
  136. OutputDebugString("PostReceive Out\n");
  137. #endif
  138. return TRUE;
  139. }
  140. int
  141. FWriteToNet(WI *pwi, LPSTR addr, int cnt)
  142. {
  143. int len = 0, retries = 0;
  144. if(pwi->nd.hsd == INVALID_SOCKET)
  145. {
  146. len = SOCKET_ERROR;
  147. goto Done;
  148. }
  149. do
  150. {
  151. len = send( pwi->nd.hsd, addr, cnt, 0 );
  152. retries ++;
  153. }
  154. while ((len == SOCKET_ERROR) && (WSAGetLastError() == WSAEWOULDBLOCK) && (retries < 5));
  155. Done:
  156. return(len);
  157. }
  158. BOOL
  159. FCommandPending(WI *pwi)
  160. {
  161. return(FALSE);
  162. }
  163. /*
  164. void
  165. FSendTM( HWND hwnd )
  166. {
  167. WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  168. unsigned char sbuf[] = { IAC, DO, TO_TM };
  169. ui.fFlushOut = 1;
  170. send( pwi->nd.hsd, ( char * )sbuf, sizeof( sbuf ), 0);
  171. }
  172. */
  173. //Our server still doesn't support urgent data handling..
  174. void
  175. FSendSynch(HWND hwnd)
  176. {
  177. WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  178. unsigned char sbuf[] = { IAC, DM };
  179. send( pwi->nd.hsd, ( char * )sbuf, 1, 0 );
  180. send( pwi->nd.hsd, ( char * )( sbuf + 1 ), 1, MSG_OOB );
  181. }
  182. void
  183. FSendTelnetCommands( HWND hwnd, char chCommand )
  184. {
  185. WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  186. unsigned char sbuf[]={ IAC , 0 };
  187. sbuf[1] = chCommand;
  188. send( pwi->nd.hsd, ( char * )sbuf, sizeof( sbuf ), 0 );
  189. }
  190. void
  191. FSendChars(HWND hwnd, WCHAR rgchChar[], int iLength )
  192. {
  193. WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  194. CHAR rgchMBChar[ SMALL_STRING ];
  195. iLength = WideCharToMultiByte( GetConsoleCP(), 0, rgchChar, iLength,
  196. rgchMBChar, (SMALL_STRING - sizeof(CHAR)), NULL, NULL );
  197. send( pwi->nd.hsd, rgchMBChar, iLength, 0 );
  198. }
  199. void
  200. FDisableFlush(HWND hwnd)
  201. {
  202. WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  203. if (ui.fFlushOut) {
  204. ui.fFlushOut = 0;
  205. DoIBMANSIOutput(pwi, &pwi->trm, strlen( ( CHAR * ) szNewLine), szNewLine);
  206. #ifdef TCPTEST
  207. OutputDebugString("Disable Flush\n");
  208. #endif
  209. }
  210. }
  211. void
  212. FProcessDont(WI *pwi, LPSTR *ps)
  213. {
  214. unsigned char sbuf[16];
  215. sbuf[0] = IAC;
  216. sbuf[1] = WONT;
  217. switch (*(unsigned char FAR *)(*ps)) {
  218. default:
  219. sbuf[2] = *(unsigned char FAR *)(*ps);
  220. break;
  221. }
  222. FWriteToNet(pwi, ( char* )sbuf, 3);
  223. if( *(*ps) == TO_NAWS )
  224. {
  225. g_bDontNAWSReceived = TRUE;
  226. }
  227. }
  228. void DoNawsSubNegotiation( WI *pwi )
  229. {
  230. unsigned char sbuf[16];
  231. INT iIndex = 0;
  232. sbuf[iIndex++] = IAC;
  233. sbuf[iIndex++] = SB;
  234. sbuf[iIndex++] = TO_NAWS;
  235. sbuf[iIndex++] = 0;
  236. sbuf[iIndex++] = ( UCHAR ) ( (pwi->sbi.srWindow.Right - pwi->sbi.srWindow.Left) + 1 ) ;
  237. sbuf[iIndex++] = 0;
  238. sbuf[iIndex++] = ( UCHAR )( ( pwi->sbi.srWindow.Bottom - pwi->sbi.srWindow.Top ) + 1 );
  239. sbuf[iIndex++] = IAC;
  240. sbuf[iIndex++] = SE;
  241. FWriteToNet(pwi, ( char* )sbuf, iIndex );
  242. }
  243. void
  244. FProcessDo(WI *pwi, LPSTR *ps)
  245. {
  246. unsigned char sbuf[16];
  247. BOOL bWriteToNet = TRUE;
  248. sbuf[0] = IAC;
  249. sbuf[1] = WONT;
  250. switch (*(unsigned char FAR *)(*ps)) {
  251. case TO_NEW_ENVIRON:
  252. sbuf[1] = WILL;
  253. sbuf[2] = TO_NEW_ENVIRON;
  254. break;
  255. case TO_NAWS:
  256. {
  257. INT iIndex = 1;
  258. if( !g_fSentWillNaws )
  259. {
  260. sbuf[iIndex++] = WILL;
  261. sbuf[iIndex++] = TO_NAWS;
  262. FWriteToNet(pwi, ( char* )sbuf, iIndex );
  263. g_fSentWillNaws = TRUE;
  264. }
  265. DoNawsSubNegotiation( pwi );
  266. pwi->nd.fRespondedToDoNAWS = TRUE;
  267. bWriteToNet = FALSE;
  268. }
  269. break;
  270. case TO_ECHO:
  271. sbuf[1] = WILL;
  272. sbuf[2] = TO_ECHO;
  273. break;
  274. case TO_BINARY:
  275. sbuf[1] = WILL;
  276. sbuf[2] = TO_BINARY;
  277. break;
  278. case TO_TERM_TYPE: /* terminal type */
  279. sbuf[1] = WILL;
  280. sbuf[2] = TO_TERM_TYPE;
  281. if( !pwi->nd.fRespondedToDoNAWS && !g_fSentWillNaws )
  282. {
  283. sbuf[3] = IAC;
  284. sbuf[4] = WILL;
  285. sbuf[5] = TO_NAWS;
  286. bWriteToNet = FALSE;
  287. FWriteToNet(pwi, ( char* )sbuf, 6);
  288. g_fSentWillNaws = TRUE;
  289. }
  290. // haven't sent the termtype over yet.
  291. pwi->trm.SentTermType = TT_UNKNOWN;
  292. break;
  293. case TO_AUTH:
  294. if( pwi->nd.fRespondedToDoAUTH )
  295. return;
  296. if( ui.bWillAUTH )
  297. sbuf[1] = WILL;
  298. sbuf[2] = TO_AUTH;
  299. pwi->nd.fRespondedToDoAUTH = TRUE;
  300. break;
  301. case TO_SGA: // will SUPPRESS-GO-AHEAD
  302. sbuf[1] = WILL;
  303. sbuf[2] = TO_SGA;
  304. break;
  305. default:
  306. sbuf[2] = *(unsigned char FAR *)(*ps);
  307. break;
  308. }
  309. if ( bWriteToNet )
  310. {
  311. FWriteToNet(pwi, ( char* )sbuf, 3);
  312. }
  313. }
  314. void
  315. FProcessWont(WI *pwi, LPSTR *ps)
  316. {
  317. unsigned char sbuf[16];
  318. sbuf[0] = IAC;
  319. sbuf[1] = DONT;
  320. switch (*(unsigned char FAR *)(*ps)) {
  321. case TO_ECHO:
  322. sbuf[2] = TO_ECHO;
  323. break;
  324. case TO_TERM_TYPE:
  325. sbuf[2] = TO_TERM_TYPE;
  326. break;
  327. case TO_TM:
  328. FDisableFlush(pwi->hwnd);
  329. return;
  330. default:
  331. sbuf[2] = *(unsigned char FAR *)(*ps);
  332. break;
  333. }
  334. FWriteToNet(pwi, ( char* )sbuf, 3);
  335. }
  336. void
  337. FProcessWill(WI *pwi, LPSTR *ps)
  338. {
  339. unsigned char sbuf[16];
  340. BOOL bWriteToNet = TRUE;
  341. sbuf[0] = IAC;
  342. sbuf[1] = DONT;
  343. switch (*(unsigned char FAR *)(*ps)) {
  344. case TO_ECHO:
  345. if( pwi->nd.fRespondedToWillEcho )
  346. return;
  347. sbuf[1] = DO;
  348. sbuf[2] = TO_ECHO;
  349. pwi->nd.fRespondedToWillEcho = TRUE;
  350. break;
  351. case TO_TM:
  352. FDisableFlush(pwi->hwnd);
  353. return;
  354. case TO_SGA:
  355. if( pwi->nd.fRespondedToWillSGA )
  356. return;
  357. sbuf[1] = DO;
  358. sbuf[2] = TO_SGA;
  359. pwi->nd.fRespondedToWillSGA = TRUE;
  360. break;
  361. case TO_BINARY:
  362. sbuf[1] = DO;
  363. sbuf[2] = TO_BINARY;
  364. break;
  365. #if 0
  366. case TO_NTLM:
  367. if ( pwi->nd.fRespondedToWillNTLM )
  368. return;
  369. if ( ui.bDoNTLM )
  370. sbuf[1] = DO;
  371. sbuf[2] = TO_NTLM;
  372. pwi->nd.fRespondedToWillNTLM = TRUE;
  373. if ( ui.bDoNTLM )
  374. {
  375. bWriteToNet = FALSE;
  376. FWriteToNet(pwi, sbuf, 3);
  377. StartNTLMAuth(pwi);
  378. }
  379. break;
  380. #endif
  381. default:
  382. sbuf[2] = *(unsigned char FAR *)(*ps);
  383. break;
  384. }
  385. if ( bWriteToNet )
  386. FWriteToNet(pwi, ( char* )sbuf, 3);
  387. }
  388. BOOL StuffEscapeIACs( PUCHAR* ppBufDest, UCHAR bufSrc[], DWORD* pdwSize )
  389. {
  390. size_t length;
  391. int cursorDest = 0;
  392. int cursorSrc = 0;
  393. BOOL found = FALSE;
  394. PUCHAR pDest = NULL;
  395. if( *pdwSize <= 0 )
  396. {
  397. return ( found );
  398. }
  399. //get the location of the first occurrence of IAC
  400. pDest = (PUCHAR) memchr( bufSrc, IAC, *pdwSize ); //attack? pdwsize could not be traced back to see if it's always valid.
  401. if( pDest == NULL )
  402. {
  403. return ( found );
  404. }
  405. *ppBufDest = (PUCHAR) malloc( *pdwSize * 2 );
  406. if( *ppBufDest == NULL )
  407. {
  408. ASSERT( ( 0, 0 ) );
  409. return ( found );
  410. }
  411. while( pDest != NULL )
  412. {
  413. //copy data upto and including that point
  414. length = (pDest - ( bufSrc + cursorSrc)) + 1 ;
  415. memcpy( *ppBufDest + cursorDest, bufSrc + cursorSrc, length ); //attack? length could not be traced back to see if it's always valid.
  416. cursorDest += length;
  417. //stuff another TC_IAC
  418. (*ppBufDest)[ cursorDest ] = IAC;
  419. cursorDest++;
  420. cursorSrc += length;
  421. pDest = (PUCHAR) memchr( bufSrc + cursorSrc, IAC,
  422. *pdwSize - cursorSrc ); //attack? pdwsize could not be traced back to see if it's always valid.
  423. }
  424. //copy remaining data
  425. memcpy( *ppBufDest + cursorDest, bufSrc + cursorSrc,
  426. *pdwSize - cursorSrc ); //attack? pdwsize could not be traced back to see if it's always valid.
  427. if( cursorDest )
  428. {
  429. *pdwSize += cursorDest - cursorSrc;
  430. found = TRUE;
  431. }
  432. return ( found );
  433. }
  434. INT GetVariable( UCHAR rgchBuffer[], CHAR szVar[] )
  435. {
  436. INT iIndex = 0;
  437. INT iVarIndex = 0;
  438. while( iIndex < MAX_BUFFER_SIZE && iVarIndex < MAX_STRING_LENGTH
  439. && rgchBuffer[ iIndex ] != VAR
  440. && rgchBuffer[ iIndex ] != USERVAR
  441. && ( !( rgchBuffer[ iIndex ] == IAC && rgchBuffer[ iIndex + 1 ] == SE ) )
  442. )
  443. {
  444. if( rgchBuffer[ iIndex ] == ESC )
  445. {
  446. //ignore ESC and take the next char as part of name
  447. iIndex++;
  448. }
  449. szVar[ iVarIndex++ ] = rgchBuffer[ iIndex++ ];
  450. }
  451. szVar[ iVarIndex ] = 0;
  452. return iIndex;
  453. }
  454. void PutDefaultVarsInBuffer( UCHAR ucBuffer[], INT *iIndex )
  455. {
  456. ASSERT( iIndex );
  457. if( wcscmp( szUserName, ( LPTSTR )L"" ) != 0 )
  458. {
  459. DWORD dwNum;
  460. ASSERT( szUser );
  461. if( *iIndex +
  462. ( strlen( USER ) + 1 ) +
  463. ( strlen( szUser ) + 1 ) +
  464. ( strlen( SYSTEMTYPE ) + 1 ) +
  465. ( strlen( WIN32_STRING ) + 1 ) > MAX_STRING_LENGTH )
  466. {
  467. ASSERT( 0 );
  468. return;
  469. }
  470. {
  471. //variable USER
  472. ucBuffer[ ( *iIndex )++ ] = VAR;
  473. strcpy( ucBuffer + ( *iIndex ), USER ); //no overflow. USER is const char *
  474. *iIndex = *iIndex + strlen( USER ) ;
  475. ucBuffer[ ( *iIndex )++ ] = VALUE;
  476. strcpy(ucBuffer+( *iIndex ), szUser ); //no overflow. SzUser is valid, NULL terminated.
  477. *iIndex = ( *iIndex ) + strlen( szUser);
  478. }
  479. {
  480. //variable SYSTEMTYPE
  481. ucBuffer[( *iIndex )++] = VAR;
  482. strcpy(ucBuffer+( *iIndex ), SYSTEMTYPE ); //no overflow. SYSTEMTYPE is const char *
  483. *iIndex = ( *iIndex ) + strlen( SYSTEMTYPE );
  484. ucBuffer[( *iIndex )++] = VALUE;
  485. strcpy(ucBuffer+( *iIndex ), WIN32_STRING );//no overflow. WIN32_STRING is const char *
  486. *iIndex = ( *iIndex ) + strlen( WIN32_STRING );
  487. }
  488. }
  489. return;
  490. }
  491. void
  492. FProcessSB(WI * pwi, LPSTR *ps, int *recvsize)
  493. {
  494. unsigned char sbuf[16];
  495. int inx;
  496. int i = 0;
  497. int cbLeft = *recvsize;
  498. //
  499. // Is the end of this option in the receive buffer?
  500. //
  501. while ( cbLeft )
  502. {
  503. if ( ((unsigned char) (*ps)[i]) == (unsigned char) SE )
  504. goto Found;
  505. cbLeft--;
  506. i++;
  507. }
  508. //
  509. // We ran out of buffer before finding the end of the option. IAC and
  510. // SB were already eaten so add them
  511. //
  512. #ifdef TCPTEST
  513. OutputDebugString("FProcessSB: saving incomplete option for next recv\n");
  514. #endif
  515. pwi->nd.lpTempBuffer[0] = (unsigned char) IAC;
  516. pwi->nd.lpTempBuffer[1] = (unsigned char) SB;
  517. for ( i = 2, cbLeft = (*recvsize+2); i < cbLeft; i++ )
  518. pwi->nd.lpTempBuffer[i] = (*ps)[i-2];
  519. pwi->nd.cbOld = *recvsize + 2;
  520. *recvsize = 0;
  521. return;
  522. Found:
  523. switch (*(unsigned char FAR *)(*ps)) {
  524. case TO_NEW_ENVIRON:
  525. //MBSC user name value now available in szUser
  526. if( *(unsigned char FAR *)(*ps+1) == TT_SEND )
  527. {
  528. PUCHAR ucServerSentBuffer = *ps;
  529. UCHAR ucBuffer[ MAX_BUFFER_SIZE + 2 ];
  530. int iIndex = 0;
  531. ucBuffer[ iIndex++ ] = ( UCHAR )IAC;
  532. ucBuffer[ iIndex++] = ( UCHAR )SB;
  533. ucBuffer[ iIndex++] = TO_NEW_ENVIRON;
  534. ucBuffer[ iIndex++] = TT_IS;
  535. inx = iIndex;
  536. if( *(unsigned char FAR *)(ucServerSentBuffer+2) == IAC &&
  537. *(unsigned char FAR *)(ucServerSentBuffer+3) == SE )
  538. {
  539. PutDefaultVarsInBuffer( ucBuffer, &inx );
  540. }
  541. else
  542. {
  543. ucServerSentBuffer = ucServerSentBuffer + 2 ; // eat TO_NEW_ENVIRON, TT_SEND
  544. while ( !( *ucServerSentBuffer == IAC && *(ucServerSentBuffer+1) == SE )
  545. && inx < MAX_BUFFER_SIZE )
  546. {
  547. CHAR szVar[ MAX_STRING_LENGTH ];
  548. CHAR *pcVal = NULL;
  549. switch( *(unsigned char FAR *)(ucServerSentBuffer) )
  550. {
  551. case VAR:
  552. ( ucServerSentBuffer )++; //eat VAR
  553. if( ( *ucServerSentBuffer == IAC &&
  554. *(ucServerSentBuffer+1) == SE ) ||
  555. *ucServerSentBuffer == USERVAR )
  556. {
  557. //send defaults
  558. PutDefaultVarsInBuffer( ucBuffer, &inx );
  559. }
  560. else
  561. {
  562. ucServerSentBuffer += GetVariable( ucServerSentBuffer, szVar ); //GetVariable returns consumed net data
  563. if( inx + strlen( szVar ) + 1 < MAX_BUFFER_SIZE )
  564. {
  565. ucBuffer[ inx++ ] = VAR;
  566. //copy name of the variable
  567. strncpy( ucBuffer+inx, szVar, MAX_BUFFER_SIZE - inx);
  568. inx += strlen( szVar );
  569. }
  570. //now copy the value if defined
  571. if( strcmp( szVar, USER ) == 0 )
  572. {
  573. if( inx + strlen( szUser ) + 1 < MAX_BUFFER_SIZE )
  574. {
  575. ucBuffer[inx++] = VALUE;
  576. strncpy(ucBuffer+inx, szUser, MAX_BUFFER_SIZE - inx );
  577. inx = inx + strlen( szUser);
  578. }
  579. }
  580. else if( strncmp( szVar, SYSTEMTYPE, strlen( SYSTEMTYPE ) ) == 0 )
  581. {
  582. if( inx + strlen( WIN32_STRING ) + 1 < MAX_BUFFER_SIZE )
  583. {
  584. ucBuffer[inx++] = VALUE;
  585. strncpy(ucBuffer+ inx, WIN32_STRING,MAX_BUFFER_SIZE - inx );
  586. inx = inx + strlen( WIN32_STRING );
  587. }
  588. }
  589. else
  590. {
  591. //do nothing. It means, variable is undefined
  592. }
  593. }
  594. break;
  595. case USERVAR:
  596. ( ucServerSentBuffer )++; //eat USERVAR
  597. if( ( *ucServerSentBuffer == IAC &&
  598. *(ucServerSentBuffer+1) == SE ) ||
  599. *ucServerSentBuffer == VAR )
  600. {
  601. //send defaults ie; NONE
  602. }
  603. else
  604. {
  605. //Send the variable that is asked for
  606. DWORD dwSize = 0;
  607. ucServerSentBuffer += GetVariable( ucServerSentBuffer, szVar );
  608. if( inx + strlen( szVar ) + 1 < MAX_BUFFER_SIZE )
  609. {
  610. ucBuffer[inx++] = USERVAR;
  611. strncpy( ucBuffer+inx, szVar,MAX_BUFFER_SIZE - inx );
  612. inx += strlen( szVar );
  613. }
  614. dwSize = GetEnvironmentVariableA( szVar, NULL, 0 );
  615. if( dwSize > 0 )
  616. {
  617. pcVal = ( CHAR * ) malloc( dwSize + DELTA ); //This delta is meant for
  618. //holding any ESC chars
  619. if( !pcVal )
  620. {
  621. return;
  622. }
  623. if( GetEnvironmentVariableA( szVar, pcVal, dwSize ) )
  624. {
  625. INT x = 0;
  626. INT iNeedForEsc = 0;
  627. CHAR cVar = VAR, cUserVar = USERVAR;
  628. x = strlen( pcVal ) - 1;
  629. while( x >= 0 )
  630. {
  631. if( pcVal[ x ] >= cVar && pcVal[ x ] <= cUserVar )
  632. {
  633. //needs an ESC char
  634. iNeedForEsc++;
  635. }
  636. x--;
  637. }
  638. if( iNeedForEsc && iNeedForEsc < DELTA )
  639. {
  640. x = strlen( pcVal );
  641. //Null char is same as of VAR. So, special case.
  642. pcVal[ x + iNeedForEsc ] = pcVal[ x-- ];
  643. while( x >= 0 )
  644. {
  645. pcVal[ x + iNeedForEsc ] = pcVal[ x ];
  646. if( pcVal[ x ] >= cVar && pcVal[ x ] <= cUserVar )
  647. {
  648. //needs an ESC char
  649. iNeedForEsc--;
  650. pcVal[ x + iNeedForEsc ] = ESC;
  651. }
  652. x--;
  653. }
  654. }
  655. if( inx + strlen( pcVal ) + 1 < MAX_STRING_LENGTH )
  656. {
  657. //write VALUE keyword
  658. ucBuffer[inx++] = VALUE;
  659. //write actual value
  660. strncpy(ucBuffer+ inx, pcVal,MAX_BUFFER_SIZE - inx );
  661. inx = inx + strlen( pcVal );
  662. }
  663. }
  664. free( pcVal );
  665. }
  666. }
  667. break;
  668. default:
  669. ASSERT( 0 ); //This should not happen. Only types we know are VAR and USERVAR
  670. break;
  671. }
  672. }
  673. }
  674. ucBuffer[inx++] = ( UCHAR )IAC;
  675. ucBuffer[inx++] = ( UCHAR )SE;
  676. FWriteToNet(pwi, ucBuffer, inx);
  677. }
  678. break;
  679. case TO_TERM_TYPE:
  680. // This is guaranteed to happen after an authentication has happened so we can start obeying the
  681. // local echo settings...
  682. ui.fDebug |= ui.honor_localecho; // restore the saved echo settings.
  683. if( *(unsigned char FAR *)(*ps+1) == TT_SEND )
  684. {
  685. sbuf[0] = IAC;
  686. sbuf[1] = SB;
  687. sbuf[2] = TO_TERM_TYPE;
  688. sbuf[3] = TT_IS;
  689. inx = 4;
  690. if( pwi->trm.SentTermType == TT_UNKNOWN &&
  691. pwi->trm.RequestedTermType != TT_UNKNOWN )
  692. {
  693. // we haven't started the negotiation yet and the user has specified
  694. // a preferred term type, so we start with that.
  695. // RequestedTermType here is the user's setting not the server's.
  696. pwi->trm.CurrentTermType = pwi->trm.RequestedTermType;
  697. pwi->trm.FirstTermTypeSent = pwi->trm.CurrentTermType;
  698. }
  699. else
  700. {
  701. pwi->trm.CurrentTermType = (pwi->trm.CurrentTermType + 1) % 4;
  702. if( pwi->trm.CurrentTermType == pwi->trm.FirstTermTypeSent )
  703. pwi->trm.CurrentTermType = pwi->trm.SentTermType;
  704. }
  705. //write maximum number of n bytes where n = sizeof(sbuf)-CurrentLength(sbuf)-2BytesForIACandSE-1ForNULL
  706. strncpy( (char *) sbuf+4, rgchTermType[pwi->trm.CurrentTermType],16 - strlen(sbuf) -2 -1);
  707. inx += strlen(rgchTermType[pwi->trm.CurrentTermType]);
  708. sbuf[inx++] = IAC;
  709. sbuf[inx++] = SE;
  710. // set the Sent TermType to what we just sent
  711. pwi->trm.SentTermType = pwi->trm.CurrentTermType ;
  712. FWriteToNet(pwi, ( char * )sbuf, inx);
  713. }
  714. break;
  715. #if 1
  716. case TO_AUTH:
  717. if( (*(unsigned char FAR *)(*ps+1) == AU_SEND) && (*(unsigned char FAR *)(*ps+2) == AUTH_TYPE_NTLM) )
  718. {
  719. if ( pwi->eState!= Connecting || !PromptUser() || !StartNTLMAuth(pwi) )
  720. {
  721. // there has been an error.
  722. pwi->eState = Telnet;
  723. sbuf[0] = IAC;
  724. sbuf[1] = SB;
  725. sbuf[2] = TO_AUTH;
  726. sbuf[3] = AU_IS;
  727. sbuf[4] = AUTH_TYPE_NULL;
  728. sbuf[5] = 0;
  729. sbuf[6] = IAC;
  730. sbuf[7] = SE;
  731. FWriteToNet(pwi, ( char * )sbuf, 8);
  732. }
  733. }
  734. else if( (*(unsigned char FAR *)(*ps+1) == AU_REPLY) && (*(unsigned char FAR *)(*ps+2) == AUTH_TYPE_NTLM) )
  735. {
  736. // ps + 3 is the modifier and for NTLM it is AUTH_CLIENT_TO_SERVER & AUTH_ONE_WAY.
  737. // ps + 4 is the NTLM accept or NTLM challenge or NTLM reject
  738. switch ( *(unsigned char FAR *)(*ps+4) )
  739. {
  740. case NTLM_CHALLENGE:
  741. if( pwi->eState != Authenticating || !DoNTLMAuth(pwi, (unsigned char FAR *)(*ps+5), *recvsize-5) )
  742. {
  743. // there has been an error.
  744. pwi->eState = Telnet;
  745. sbuf[0] = IAC;
  746. sbuf[1] = SB;
  747. sbuf[2] = TO_AUTH;
  748. sbuf[3] = AU_IS;
  749. sbuf[4] = AUTH_TYPE_NULL;
  750. sbuf[5] = 0;
  751. sbuf[6] = IAC;
  752. sbuf[7] = SE;
  753. FWriteToNet(pwi, ( char * )sbuf, 8);
  754. }
  755. break;
  756. case NTLM_ACCEPT:
  757. //fall through
  758. case NTLM_REJECT:
  759. //fall through
  760. default:
  761. pwi->eState = Telnet;
  762. if( pwi->eState == Authenticating || pwi->eState == AuthChallengeRecvd )
  763. {
  764. NTLMCleanup();
  765. }
  766. break;
  767. }
  768. }
  769. else
  770. {
  771. pwi->eState = Telnet;
  772. sbuf[0] = IAC;
  773. sbuf[1] = SB;
  774. sbuf[2] = TO_AUTH;
  775. sbuf[3] = AU_IS;
  776. sbuf[4] = AUTH_TYPE_NULL;
  777. sbuf[5] = 0;
  778. sbuf[6] = IAC;
  779. sbuf[7] = SE;
  780. FWriteToNet(pwi, ( char * )sbuf, 8);
  781. }
  782. break;
  783. #endif
  784. default:
  785. break;
  786. }
  787. while (*(unsigned char FAR *)(*ps) != SE) {
  788. (*ps) = (char FAR *)(*ps) + 1;
  789. *recvsize = *recvsize - 1;
  790. }
  791. //
  792. // Do one more to step over the SE
  793. //
  794. (*ps) = (char FAR *)(*ps) + 1;
  795. *recvsize = *recvsize - 1;
  796. }
  797. void
  798. FProcessIAC(
  799. HWND hwnd,
  800. WI * pwi,
  801. LPSTR * ps,
  802. LPSTR * pd,
  803. int * recvsize,
  804. int * t_size)
  805. {
  806. UCHAR ch = *(unsigned char FAR *)(*ps);
  807. ui.nottelnet = FALSE; // We can safely say that we are talking to a telnet server now...
  808. //
  809. // The IAC has already been subtracted from *recvsize
  810. //
  811. //
  812. // Make sure we have enough recv buffer to process the rest of the IAC
  813. // We know the DO, DONT etc. options always take two bytes plus the IAC.
  814. //
  815. if ( ((ch == DONT || ch == DO ||
  816. ch == WILL || ch == WONT) && *recvsize < 2) ||
  817. (ch != SB && *recvsize < 1) )
  818. {
  819. int i;
  820. #ifdef TCPTEST
  821. OutputDebugString("FProcessIAC: saving incomplete option for next recv\n");
  822. #endif
  823. //
  824. // IAC was previously eaten
  825. //
  826. pwi->nd.lpTempBuffer[0] = (unsigned char) IAC;
  827. for ( i = 1; i < (*recvsize+1); i++ )
  828. pwi->nd.lpTempBuffer[i] = (*ps)[i-1];
  829. pwi->nd.cbOld = *recvsize + 1;
  830. *recvsize = 0;
  831. return;
  832. }
  833. switch (*(unsigned char FAR *)(*ps)) {
  834. case DONT:
  835. (*ps) = (char FAR *)(*ps) + 1;
  836. /* process options */
  837. FProcessDont(pwi, ps);
  838. #ifdef TCPTEST
  839. OutputDebugString("DONT \n");
  840. #endif
  841. (*ps) = (char FAR *)(*ps) + 1;
  842. *recvsize = *recvsize - 2;
  843. break;
  844. case DO:
  845. (*ps) = (char FAR *)(*ps) + 1;
  846. /* process options */
  847. FProcessDo(pwi, ps);
  848. #ifdef TCPTEST
  849. OutputDebugString("DO \n");
  850. #endif
  851. (*ps) = (char FAR *)(*ps) + 1;
  852. *recvsize = *recvsize - 2;
  853. break;
  854. case WONT:
  855. (*ps) = (char FAR *)(*ps) + 1;
  856. /* process options */
  857. FProcessWont(pwi, ps);
  858. #ifdef TCPTEST
  859. OutputDebugString("WONT \n");
  860. #endif
  861. (*ps) = (char FAR *)(*ps) + 1;
  862. *recvsize = *recvsize - 2;
  863. break;
  864. case WILL:
  865. (*ps) = (char FAR *)(*ps) + 1;
  866. /* process options */
  867. FProcessWill(pwi, ps);
  868. #ifdef TCPTEST
  869. OutputDebugString("WILL \n");
  870. #endif
  871. (*ps) = (char FAR *)(*ps) + 1;
  872. *recvsize = *recvsize - 2;
  873. break;
  874. case SB:
  875. (*ps) = (char FAR *)(*ps) + 1;
  876. *recvsize -= 1;
  877. /* process options */
  878. FProcessSB(pwi, ps, recvsize);
  879. break;
  880. default:
  881. (*ps) = (char FAR *)(*ps) + 1;
  882. *recvsize -= 1;
  883. break;
  884. }
  885. }
  886. #ifdef TCPTEST
  887. VOID DumpBuffer( VOID FAR * pbuff, DWORD cb )
  888. {
  889. #define NUM_CHARS 16
  890. DWORD i, limit;
  891. CHAR TextBuffer[NUM_CHARS + 1];
  892. LPBYTE BufferPtr;
  893. if ( !pbuff )
  894. {
  895. OutputDebugString("No buffer\n");
  896. return;
  897. }
  898. BufferPtr = (LPBYTE) pbuff;
  899. //
  900. // Hex dump of the bytes
  901. //
  902. limit = ((cb - 1) / NUM_CHARS + 1) * NUM_CHARS;
  903. for (i = 0; i < limit; i++) {
  904. if (i < cb) {
  905. snprintf(DebugBuffer,sizeof(DebugBuffer)-1, "%02x ", BufferPtr[i]);
  906. OutputDebugString( DebugBuffer );
  907. if (BufferPtr[i] < 31 ) {
  908. TextBuffer[i % NUM_CHARS] = '.';
  909. } else if (BufferPtr[i] == '\0') {
  910. TextBuffer[i % NUM_CHARS] = ' ';
  911. } else {
  912. TextBuffer[i % NUM_CHARS] = (CHAR) BufferPtr[i];
  913. }
  914. } else {
  915. OutputDebugString(" ");
  916. TextBuffer[i % NUM_CHARS] = ' ';
  917. }
  918. if ((i + 1) % NUM_CHARS == 0) {
  919. TextBuffer[NUM_CHARS] = 0;
  920. snprintf(DebugBuffer,sizeof(DebugBuffer)-1, " %s\n", TextBuffer);
  921. OutputDebugString( DebugBuffer );
  922. }
  923. }
  924. }
  925. #endif
  926. void FProcessSessionData( int cBytes, PUCHAR pchNBBuffer, WI *pwi )
  927. {
  928. WaitForSingleObject( g_hCaptureConsoleEvent, INFINITE );
  929. WaitForSingleObject( g_hRemoteNEscapeModeDataSync, INFINITE );
  930. if( pwi->hOutput != g_hSessionConsoleBuffer )
  931. {
  932. pwi->hOutput = g_hSessionConsoleBuffer;
  933. SetConsoleActiveScreenBuffer(g_hSessionConsoleBuffer);
  934. }
  935. /*This is needed so that we don't write data to the session even after disconnection of client */
  936. if( !fConnected )
  937. {
  938. return;
  939. }
  940. ResetEvent( g_hRemoteNEscapeModeDataSync );
  941. if( pwi->trm.CurrentTermType == TT_VTNT )
  942. {
  943. if( !DoVTNTOutput(pwi, &pwi->trm, cBytes, pchNBBuffer) )
  944. {
  945. //
  946. // The following two lines were originally added as a
  947. // mechanism of defaulting to VT100 in case of some servers
  948. // accepting VTNT, during term type negotiation, even though
  949. // in reality they do not support VTNT. Specifically, Linux
  950. // was showing this behavior during our testing. But the
  951. // function DoVTNTOutput returns FALSE even in other cases
  952. // such as, when we get some junk data from the server. In
  953. // such cases we should not call DoIBMANSIOutput (bug 1119).
  954. //
  955. pwi->trm.CurrentTermType = TT_ANSI;
  956. DoIBMANSIOutput(pwi, &pwi->trm, cBytes, pchNBBuffer);
  957. }
  958. }
  959. else
  960. {
  961. DoIBMANSIOutput(pwi, &pwi->trm, cBytes, pchNBBuffer);
  962. }
  963. pwi->ichTelXfer = 0;
  964. SetEvent( g_hRemoteNEscapeModeDataSync );
  965. }
  966. void
  967. FProcessFDRead(HWND hwnd)
  968. {
  969. WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  970. int recvsize, t_size;
  971. LPSTR ps, pd;
  972. //
  973. // pwi->nd.cbOld Is the number of bytes left over from the previous
  974. // packet that we kept in pwi->nd.lpTempBuffer
  975. //
  976. if ((recvsize=recv(pwi->nd.hsd,
  977. pwi->nd.lpTempBuffer + pwi->nd.cbOld,
  978. READ_BUF_SZ - pwi->nd.cbOld,
  979. 0)) < 0)
  980. {
  981. return;
  982. }
  983. //
  984. // Fix to bug 284
  985. //
  986. Sleep(0);
  987. recvsize += pwi->nd.cbOld;
  988. pwi->nd.cbOld = 0;
  989. ps = pwi->nd.lpTempBuffer;
  990. pd = pwi->nd.lpReadBuffer;
  991. t_size = 0;
  992. while( recvsize-- )
  993. {
  994. if( *(unsigned char FAR *) ps == (unsigned char)IAC )
  995. {
  996. if( recvsize == 0 )
  997. {
  998. pwi->nd.lpTempBuffer[0] = (unsigned char) IAC;
  999. pwi->nd.cbOld = 1;
  1000. break;
  1001. }
  1002. ps++;
  1003. if( *(unsigned char FAR *)ps == (unsigned char)IAC )
  1004. {
  1005. //
  1006. // This was an escaped IAC so put it in the normal
  1007. // input buffer
  1008. //
  1009. ps++;
  1010. *(unsigned char FAR *)pd = (unsigned char)IAC;
  1011. pd++;
  1012. recvsize--;
  1013. t_size++;
  1014. }
  1015. else
  1016. {
  1017. FProcessIAC(hwnd, pwi, &ps, &pd, &recvsize, &t_size);
  1018. }
  1019. }
  1020. else
  1021. {
  1022. *(char FAR *)pd = *(char FAR *)ps;
  1023. pd++;
  1024. ps++;
  1025. t_size++;
  1026. }
  1027. }
  1028. if( t_size )
  1029. {
  1030. /* add received data to buffer */
  1031. if ( !(ui.fFlushOut) || ui.nottelnet )
  1032. {
  1033. FProcessSessionData( t_size, pwi->nd.lpReadBuffer, pwi );
  1034. }
  1035. }
  1036. }
  1037. void
  1038. FProcessFDOOB(HWND hwnd)
  1039. {
  1040. WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  1041. int recvsize;
  1042. LPSTR ps;
  1043. if ((recvsize=recv(pwi->nd.hsd, pwi->nd.lpTempBuffer,
  1044. READ_BUF_SZ, MSG_OOB)) < 0) {
  1045. #ifdef TCPTEST
  1046. OutputDebugString("recv error \n");
  1047. #endif
  1048. return;
  1049. }
  1050. ps = pwi->nd.lpTempBuffer;
  1051. if (*(unsigned char *)ps == (unsigned char)DM)
  1052. {
  1053. #ifdef TCPTEST
  1054. OutputDebugString("DM received\n");
  1055. #endif
  1056. FDisableFlush(hwnd);
  1057. }
  1058. }
  1059. BOOL
  1060. FAttemptServerConnect(WI *pwi, LPSTR szHostName, LPNETDATA lpData)
  1061. {
  1062. BOOL got_connected = FALSE;
  1063. struct servent *serv;
  1064. struct sockaddr_storage myad;
  1065. int on = 1;
  1066. char szService[256];
  1067. char *pszService = NULL;
  1068. struct addrinfo *aiTemp = NULL;
  1069. g_dwSockErr = 0; //Intialize to no error
  1070. if(rgService)
  1071. {
  1072. pszService = szService;
  1073. _snprintf(pszService,sizeof(szService)-1, "%d",rgService);
  1074. }
  1075. else
  1076. {
  1077. got_connected = FALSE;
  1078. return(got_connected);
  1079. }
  1080. strncpy(lpData->szHostName, szHostName,sizeof(lpData->szHostName));
  1081. if(getaddrinfo(szHostName, pszService, NULL, &lpData->ai ) != 0 )
  1082. {
  1083. got_connected = FALSE;
  1084. return(got_connected);
  1085. }
  1086. aiTemp = lpData->ai;
  1087. ui.nottelnet = TRUE; // Assume that it is not a telnet server for starters, later when it is set this flag... to false.
  1088. ui.honor_localecho = (ui.fDebug & fdwLocalEcho); // Save this and restore after a logon has happned in case of telnet
  1089. ui.fDebug &= ~fdwLocalEcho; // Clear it.
  1090. //Continue till connection is successfully established or till the list is exausted
  1091. while(aiTemp)
  1092. {
  1093. if ((lpData->hsd = socket( aiTemp->ai_family, SOCK_STREAM, 0)) == INVALID_SOCKET)
  1094. {
  1095. DEBUG_PRINT(("socket failed \n"));
  1096. aiTemp = aiTemp->ai_next;
  1097. continue;
  1098. }
  1099. SfuZeroMemory(&myad, sizeof(myad)); //no overflow. Size is constant.
  1100. myad.ss_family = (u_short)aiTemp->ai_family;
  1101. if(bind( lpData->hsd, (struct sockaddr *)&myad, sizeof(myad))<0)
  1102. {
  1103. DEBUG_PRINT(("bind failed\n"));
  1104. closesocket( lpData->hsd );
  1105. lpData->hsd = INVALID_SOCKET;
  1106. aiTemp = aiTemp->ai_next;
  1107. continue;
  1108. }
  1109. on = 1;
  1110. {
  1111. BOOL value_to_set = TRUE;
  1112. setsockopt(
  1113. lpData->hsd,
  1114. SOL_SOCKET,
  1115. SO_DONTLINGER,
  1116. ( char * )&value_to_set,
  1117. sizeof( value_to_set )
  1118. );
  1119. }
  1120. if( setsockopt( lpData->hsd, SOL_SOCKET, SO_OOBINLINE,
  1121. (char *)&on, sizeof(on) ) < 0)
  1122. {
  1123. g_dwSockErr = WSAGetLastError();
  1124. closesocket( lpData->hsd );
  1125. lpData->hsd = INVALID_SOCKET;
  1126. got_connected = FALSE;
  1127. DEBUG_PRINT(("setsockopt SO_OOBINLINE failed\n"));
  1128. DEBUG_PRINT(("FAttemptServerConnect Out\n"));
  1129. freeaddrinfo(lpData->ai);
  1130. lpData->ai = NULL;
  1131. return(got_connected);
  1132. }
  1133. else
  1134. DEBUG_PRINT(("setsockopt SO_OOBINLINE worked\n"));
  1135. if(SafeSetSocketOptions(lpData->hsd) < 0)
  1136. {
  1137. g_dwSockErr = WSAGetLastError();
  1138. closesocket( lpData->hsd );
  1139. lpData->hsd = INVALID_SOCKET;
  1140. got_connected = FALSE;
  1141. DEBUG_PRINT(("setsockopt SO_EXCLUSIVEADDRUSE failed\n"));
  1142. DEBUG_PRINT(("FAttemptServerConnect Out\n"));
  1143. freeaddrinfo(lpData->ai);
  1144. lpData->ai = NULL;
  1145. return(got_connected);
  1146. }
  1147. // ================================================================
  1148. // MohsinA, 09-Dec-96.
  1149. if(connect( lpData->hsd, (PVOID)aiTemp->ai_addr,aiTemp->ai_addrlen )<0)
  1150. {
  1151. DEBUG_PRINT(("connect failed\n"));
  1152. closesocket( lpData->hsd );
  1153. lpData->hsd = INVALID_SOCKET;
  1154. aiTemp = aiTemp->ai_next;
  1155. continue;
  1156. }
  1157. break;
  1158. }
  1159. freeaddrinfo(lpData->ai);
  1160. lpData->ai = NULL;
  1161. if(aiTemp == NULL)
  1162. {
  1163. DEBUG_PRINT(("FAttemptServerConnect Out\n"));
  1164. g_dwSockErr = WSAGetLastError();
  1165. if(lpData->hsd != INVALID_SOCKET)
  1166. closesocket( lpData->hsd );
  1167. lpData->hsd = INVALID_SOCKET;
  1168. got_connected = FALSE;
  1169. return(got_connected);
  1170. }
  1171. aiTemp=NULL;
  1172. // ================================================================
  1173. lpData->SessionNumber = 1;
  1174. if (lpData->SessionNumber != nSessionNone)
  1175. {
  1176. DEBUG_PRINT(("sess# <> nsessnone\n"));
  1177. /* post Async select */
  1178. if (WSAAsyncSelect( lpData->hsd, pwi->hwnd, WS_ASYNC_SELECT,
  1179. (FD_READ | FD_WRITE | FD_CLOSE | FD_OOB)) < 0)
  1180. {
  1181. g_dwSockErr = WSAGetLastError();
  1182. closesocket( lpData->hsd );
  1183. lpData->hsd = INVALID_SOCKET;
  1184. got_connected = FALSE;
  1185. lpData->SessionNumber = nSessionNone;
  1186. DEBUG_PRINT(("WSAAsyncSelect failed\n"));
  1187. DEBUG_PRINT(("FAttemptServerConnect Out\n"));
  1188. return(got_connected);
  1189. }
  1190. else
  1191. DEBUG_PRINT(("WSAAsyncSelect worked\n"));
  1192. got_connected = TRUE;
  1193. }
  1194. else
  1195. DEBUG_PRINT(("sess# <> nsessnone\n"));
  1196. DEBUG_PRINT(("FAttemptServerConnect Out\n"));
  1197. return got_connected;
  1198. }
  1199. void
  1200. FCloseConnection(HWND hwnd)
  1201. {
  1202. WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);
  1203. if(pwi->nd.hsd != INVALID_SOCKET)
  1204. {
  1205. closesocket( pwi->nd.hsd );
  1206. pwi->nd.hsd = INVALID_SOCKET;
  1207. }
  1208. }
  1209. #endif
  1210. #ifdef __NOT_USED
  1211. #define INC(i) (((i)+1 == DATA_BUF_SZ) ? 0 : (i)+1)
  1212. #define DEC(i) (((i)-1 < 0) ? DATA_BUF_SZ-1 : (i)-1)
  1213. WORD
  1214. WGetData(LPNETDATA lpData, LPSTR lpBuffer, WORD cLen)
  1215. {
  1216. WORD cb;
  1217. #ifdef TCPTEST
  1218. snprintf(DebugBuffer,sizeof(DebugBuffer)-1, "WGetData length %d\n", cLen);
  1219. OutputDebugString(DebugBuffer);
  1220. #endif
  1221. if (lpData->iHead < lpData->iTail)
  1222. {
  1223. cb = ( USHORT ) ( (cLen < (lpData->iTail - lpData->iHead - 1))
  1224. ? cLen : (lpData->iTail - lpData->iHead - 1) );
  1225. memcpy(lpBuffer, &lpData->achData[lpData->iHead+1], cb); //Attack ? size not known. No caller.
  1226. lpData->iHead = ( USHORT ) ( lpData->iHead + cb );
  1227. }
  1228. else
  1229. {
  1230. for(cb=0;
  1231. (cb<cLen) && ((WORD)INC(lpData->iHead) != lpData->iTail);
  1232. ++cb)
  1233. {
  1234. lpData->iHead = ( USHORT ) INC(lpData->iHead);
  1235. *lpBuffer++ = lpData->achData[lpData->iHead];
  1236. }
  1237. }
  1238. #ifdef TCPTEST
  1239. snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "WGetData returning %d bytes (head = %d, tail = %d)\n",
  1240. cb,
  1241. lpData->iHead,
  1242. lpData->iTail );
  1243. OutputDebugString(DebugBuffer);
  1244. #endif
  1245. return cb;
  1246. }
  1247. BOOL
  1248. FStoreData(LPNETDATA lpData, int max)
  1249. {
  1250. BOOL fSuccess = TRUE;
  1251. WORD tail = lpData->iTail;
  1252. LPSTR p = lpData->lpReadBuffer;
  1253. #ifdef TCPTEST
  1254. snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "FStoreData max %d, (head = %d, tail = %d)\n",
  1255. max,
  1256. tail,
  1257. lpData->iHead );
  1258. OutputDebugString(DebugBuffer);
  1259. #endif
  1260. if ((max+tail) < DATA_BUF_SZ)
  1261. {
  1262. memcpy(&lpData->achData[tail], p, max); //Attack ? Size not known. No caller.
  1263. tail = ( USHORT ) ( tail + max );
  1264. }
  1265. else
  1266. {
  1267. WORD head = lpData->iHead;
  1268. int i;
  1269. for (i=0; i<max; ++i)
  1270. {
  1271. if (tail == head)
  1272. {
  1273. /* the buffer is full! Rest of the data will be lost */
  1274. fSuccess = FALSE;
  1275. break;
  1276. }
  1277. else
  1278. {
  1279. lpData->achData[tail] = *p++;
  1280. tail = ( USHORT ) INC(tail);
  1281. }
  1282. }
  1283. }
  1284. lpData->iTail = tail;
  1285. #ifdef TCPTEST
  1286. snprintf(DebugBuffer, sizeof(DebugBuffer)-1, "FStoreData returning %d\n",
  1287. fSuccess );
  1288. OutputDebugString(DebugBuffer);
  1289. #endif
  1290. return fSuccess;
  1291. }
  1292. #endif
  1293. void CALLBACK
  1294. NBReceiveData(PVOID pncb)
  1295. {
  1296. }
  1297. /* following four routines modified from VTP's routines. */
  1298. BOOL
  1299. FTelXferStart(WI *pwi, int nSessionNumber)
  1300. {
  1301. #ifdef TELXFER
  1302. unsigned short u;
  1303. char rgchFileOrig[OFS_MAXPATHNAME];
  1304. char rgchFile[OFS_MAXPATHNAME];
  1305. xfGetData(0, (char *)&u, 2, nSessionNumber); // Mode
  1306. SfuZeroMemory(&pwi->svi, sizeof(SVI)); //no overflow. Size is constant
  1307. pwi->svi.hfile = INVALID_HANDLE_VALUE;
  1308. pwi->svi.lExit = -1;
  1309. pwi->svi.lCleanup = -1;
  1310. if (u != 0) // For now must be zero
  1311. return FALSE;
  1312. pwi->trm.fHideCursor = TRUE;
  1313. xfGetData(1, (char *)&u, 2, nSessionNumber); // Length of name
  1314. xfGetData(2, rgchFileOrig, u, nSessionNumber); // Name
  1315. xfGetData(3, (char *)&pwi->svi.cbFile, 4, nSessionNumber); // Filesize
  1316. lstrcpyn(rgchFile, rgchFileOrig, OFS_MAXPATHNAME -1);
  1317. /* If the user doesn't have the shift key down, prompt for */
  1318. /* a directory and name for the file */
  1319. if (!(ui.fPrompt & fdwSuppressDestDirPrompt) &&
  1320. (GetAsyncKeyState(VK_SHIFT) >= 0))
  1321. {
  1322. if ( !FGetFileName(hwnd, rgchFile, NULL) )
  1323. {
  1324. goto err;
  1325. }
  1326. }
  1327. pwi->svi.hfile = CreateFile(rgchFile, GENERIC_WRITE | GENERIC_READ,
  1328. FILE_SHARE_READ, NULL,
  1329. CREATE_ALWAYS,
  1330. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  1331. NULL);
  1332. if (pwi->svi.hfile == INVALID_HANDLE_VALUE)
  1333. {
  1334. ErrorMessage(szCantOpenFile, szAppName);
  1335. goto err;
  1336. }
  1337. pwi->svi.puchBuffer = LocalAlloc(LPTR, SV_DATABUF);
  1338. if (pwi->svi.puchBuffer == NULL)
  1339. {
  1340. ErrorMessage(szOOM, szAppName);
  1341. goto err;
  1342. }
  1343. pwi->svi.nSessionNumber = nSessionNumber;
  1344. pwi->svi.hthread = CreateThread(NULL, 0, SVReceive, &pwi->svi,
  1345. CREATE_SUSPENDED, &pwi->svi.dwThreadId);
  1346. if (pwi->svi.hthread == NULL)
  1347. {
  1348. ErrorMessage(szNoThread, szAppName);
  1349. goto err;
  1350. }
  1351. // Skip 4 which is ^D
  1352. xfPutc(5, nSessionNumber); // Get file
  1353. _snwprintf(rgchFile, OFS_MAXPATHNAME -1, szBannerMessage, rgchFileOrig, pwi->svi.cbFile);
  1354. DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(rgchFile), rgchFile);
  1355. DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(szInitialProgress), szInitialProgress);
  1356. /* In case the screen just scrolled up, paint the window */
  1357. UpdateWindow( hwnd );
  1358. ResumeThread( pwi->svi.hthread );
  1359. return TRUE;
  1360. err:
  1361. if ( pwi )
  1362. {
  1363. if (pwi->svi.puchBuffer != NULL)
  1364. LocalFree( (HANDLE)pwi->svi.puchBuffer );
  1365. if (pwi->svi.hfile != INVALID_HANDLE_VALUE)
  1366. CloseHandle( pwi->svi.hfile );
  1367. SfuZeroMemory(&pwi->svi, sizeof(SVI)); //no overflow. size is constant.
  1368. pwi->svi.hfile = INVALID_HANDLE_VALUE;
  1369. pwi->svi.lExit = -1;
  1370. pwi->svi.lCleanup = -1;
  1371. }
  1372. pwi->trm.fHideCursor = FALSE;
  1373. return FALSE;
  1374. #else
  1375. return TRUE;
  1376. #endif
  1377. }
  1378. BOOL
  1379. FTelXferEnd(WI *pwi, DWORD dwWhy)
  1380. {
  1381. #ifdef TELXFER
  1382. DWORD dwStatus = NO_ERROR;
  1383. BOOL fTransferOK = FALSE;
  1384. BOOL fAbortDownload = FALSE;
  1385. BOOL fCleanup = FALSE;
  1386. LPNETDATA lpData = &pwi->nd;
  1387. SVI *psvi = &pwi->svi;
  1388. MSG msg;
  1389. switch ( dwWhy )
  1390. {
  1391. case SV_DISCONNECT:
  1392. case SV_HANGUP:
  1393. case SV_QUIT:
  1394. if (InterlockedIncrement(&psvi->lExit) == 0)
  1395. {
  1396. if (psvi->hthread != NULL)
  1397. {
  1398. (void)GetExitCodeThread(psvi->hthread, &dwStatus);
  1399. if (dwStatus == STILL_ACTIVE)
  1400. {
  1401. if (MessageBox(hwnd, szAbortDownload, szAppName,
  1402. MB_DEFBUTTON2 | MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
  1403. {
  1404. fAbortDownload = fCleanup = TRUE;
  1405. }
  1406. /* See if the thread has finished yet */
  1407. GetExitCodeThread(psvi->hthread, &dwStatus);
  1408. if ( fAbortDownload )
  1409. {
  1410. /* If the thread hasn't finished yet, tell it to stop */
  1411. if (dwStatus == STILL_ACTIVE)
  1412. {
  1413. HCURSOR hcursorOld;
  1414. hcursorOld = SetCursor( LoadCursor(NULL, IDC_WAIT));
  1415. psvi->dwCommand = 1;
  1416. WaitForSingleObject(psvi->hthread, INFINITE);
  1417. GetExitCodeThread(psvi->hthread, &dwStatus);
  1418. (void)SetCursor( hcursorOld );
  1419. }
  1420. /* "Eat" any progress messages that might be around */
  1421. while (PeekMessage(&msg, hwnd, SV_PROGRESS, SV_DONE,
  1422. PM_REMOVE))
  1423. {
  1424. if (msg.message == SV_PROGRESS)
  1425. {
  1426. TranslateMessage( &msg );
  1427. DispatchMessage( &msg );
  1428. }
  1429. }
  1430. }
  1431. else if (dwStatus != STILL_ACTIVE)
  1432. {
  1433. fCleanup = TRUE;
  1434. }
  1435. }
  1436. else
  1437. {
  1438. fAbortDownload = fCleanup = TRUE;
  1439. }
  1440. /* If we've stopped the download, then close the thread */
  1441. if ( fCleanup )
  1442. {
  1443. CloseHandle( psvi->hthread );
  1444. psvi->hthread = NULL;
  1445. if (lpData->SessionNumber != nSessionNone)
  1446. {
  1447. xfPutc((char)(!fTransferOK ? 0x7F : 0x06),
  1448. lpData->SessionNumber);
  1449. if ( !fAbortDownload )
  1450. (void)FPostReceive( lpData );
  1451. }
  1452. }
  1453. if (dwStatus == NO_ERROR)
  1454. fTransferOK = TRUE;
  1455. }
  1456. InterlockedDecrement( &psvi->lExit );
  1457. /* If the thread wasn't aborted and it hasn't finished, return */
  1458. if (!fAbortDownload && !fCleanup)
  1459. return fAbortDownload;
  1460. }
  1461. else
  1462. {
  1463. InterlockedDecrement( &psvi->lExit );
  1464. break;
  1465. }
  1466. case SV_DONE:
  1467. if (dwWhy == SV_DONE)
  1468. {
  1469. fAbortDownload = fCleanup = TRUE;
  1470. }
  1471. /* If we're the only thread in the function, close everything down */
  1472. if (InterlockedIncrement(&psvi->lExit) == 0)
  1473. {
  1474. if (psvi->hthread != NULL)
  1475. {
  1476. WaitForSingleObject(psvi->hthread, INFINITE);
  1477. GetExitCodeThread(psvi->hthread, &dwStatus);
  1478. CloseHandle( psvi->hthread );
  1479. psvi->hthread = NULL;
  1480. if (dwStatus == NO_ERROR)
  1481. fTransferOK = TRUE;
  1482. }
  1483. }
  1484. /* Do cleanup of struct only once */
  1485. if ((InterlockedIncrement(&psvi->lCleanup) == 0) &&
  1486. (psvi->puchBuffer != NULL))
  1487. {
  1488. LocalFree( (HANDLE)psvi->puchBuffer );
  1489. psvi->puchBuffer = NULL;
  1490. if (psvi->hfile != INVALID_HANDLE_VALUE)
  1491. {
  1492. CloseHandle( psvi->hfile );
  1493. psvi->hfile = INVALID_HANDLE_VALUE;
  1494. }
  1495. psvi->cbFile = 0;
  1496. psvi->cbReadTotal = 0;
  1497. psvi->dwCommand = 0;
  1498. psvi->dwThreadId = 0;
  1499. psvi->nSessionNumber = nSessionNone;
  1500. if ((dwStatus == NO_ERROR) || (dwStatus == ERROR_OPERATION_ABORTED))
  1501. {
  1502. lstrcpyn(pchNBBuffer, szSendTelEnd,sizeof(pchNBBuffer)-1);
  1503. }
  1504. else
  1505. {
  1506. _snwprintf(pchNBBuffer,sizeof(pchNBBuffer)-1,szSendTelError, dwStatus);
  1507. }
  1508. DoIBMANSIOutput(hwnd, &pwi->trm, lstrlen(pchNBBuffer), pchNBBuffer);
  1509. pwi->ichTelXfer = 0;
  1510. pwi->trm.fHideCursor = FALSE;
  1511. }
  1512. InterlockedDecrement( &psvi->lCleanup );
  1513. if ((dwWhy == SV_DONE) && (lpData->SessionNumber != nSessionNone))
  1514. {
  1515. xfPutc((char)(!fTransferOK ? 0x7F : 0x06), lpData->SessionNumber);
  1516. (void)FPostReceive( lpData );
  1517. }
  1518. InterlockedDecrement( &psvi->lExit );
  1519. break;
  1520. default:
  1521. break;
  1522. }
  1523. return fAbortDownload;
  1524. #else
  1525. return TRUE;
  1526. #endif
  1527. }
  1528. #ifdef TELXFER
  1529. static void
  1530. xfGetData(char c, char *pchBuffer, DWORD cbBuffer, int nSessionNumber)
  1531. {
  1532. DWORD cbRead;
  1533. xfPutc(c, nSessionNumber);
  1534. while ( cbBuffer )
  1535. {
  1536. cbRead = xfGetSomeData(pchBuffer, cbBuffer, nSessionNumber);
  1537. if (cbRead == 0)
  1538. break;
  1539. cbBuffer -= cbRead;
  1540. pchBuffer += cbRead;
  1541. }
  1542. }
  1543. #endif
  1544. #ifdef USETCP
  1545. #ifdef TELXFER
  1546. static DWORD
  1547. xfGetSomeData(char *pchBuffer, DWORD cbBuffer, int nSessionNumber)
  1548. {
  1549. return 1;
  1550. }
  1551. #endif //TELXFER
  1552. #ifdef TELXFER
  1553. static void
  1554. xfPutc(char c, int nSessionNumber)
  1555. {
  1556. }
  1557. #endif
  1558. #endif
  1559. #ifdef TELXFER
  1560. BOOL
  1561. FGetFileName(HWND hwndOwner, char *rgchFile, char *rgchTitle)
  1562. {
  1563. OPENFILENAME ofn;
  1564. /* Fill in struct. */
  1565. ofn.lStructSize = sizeof(ofn);
  1566. ofn.hwndOwner = hwndOwner;
  1567. ofn.hInstance = NULL;
  1568. ofn.lpstrFilter = (LPSTR) szAllFiles;
  1569. ofn.lpstrCustomFilter = (LPSTR) NULL;
  1570. ofn.nMaxCustFilter = 0;
  1571. ofn.nFilterIndex = 0;
  1572. ofn.lpstrFile = (LPSTR) rgchFile;
  1573. ofn.nMaxFile = OFS_MAXPATHNAME;
  1574. ofn.lpstrFileTitle = (LPSTR) rgchTitle;
  1575. ofn.nMaxFileTitle = OFS_MAXPATHNAME;
  1576. ofn.lpstrInitialDir = (LPSTR) 0;
  1577. ofn.lpstrTitle = (LPSTR) szDownloadAs;
  1578. ofn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN |
  1579. OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
  1580. ofn.nFileOffset = 0;
  1581. ofn.nFileExtension = 0;
  1582. ofn.lpstrDefExt = (LPSTR) NULL;
  1583. ofn.lCustData = 0;
  1584. ofn.lpfnHook = NULL;
  1585. ofn.lpTemplateName = NULL;
  1586. if ( !GetSaveFileName(&ofn) )
  1587. {
  1588. return FALSE;
  1589. }
  1590. return TRUE;
  1591. }
  1592. #endif
  1593. DWORD WINAPI
  1594. SVReceive(SVI *psvi)
  1595. {
  1596. DWORD dwReturn = NO_ERROR;
  1597. #ifdef TELXFER
  1598. if ( psvi )
  1599. {
  1600. while ((psvi->cbFile > 0) && (psvi->dwCommand == 0))
  1601. {
  1602. DWORD cbSomeData;
  1603. DWORD cbRead;
  1604. cbRead = 0;
  1605. while ((psvi->cbFile > 0) && (cbRead < 1024))
  1606. {
  1607. cbSomeData = xfGetSomeData(psvi->puchBuffer+cbRead,
  1608. (unsigned short) 0x4000 - cbRead,
  1609. psvi->nSessionNumber);
  1610. if (cbSomeData > psvi->cbFile)
  1611. cbSomeData = psvi->cbFile;
  1612. psvi->cbFile -= cbSomeData;
  1613. cbRead += cbSomeData;
  1614. }
  1615. if (!WriteFile(psvi->hfile, psvi->puchBuffer, cbRead,
  1616. &cbSomeData, NULL))
  1617. {
  1618. dwReturn = GetLastError();
  1619. break;
  1620. }
  1621. psvi->cbReadTotal += cbRead;
  1622. PostMessage(hwndMain, SV_PROGRESS, 0, psvi->cbReadTotal);
  1623. }
  1624. /* caller must've signaled and waited for thread to stop */
  1625. if ((dwReturn == NO_ERROR) && (psvi->dwCommand != 0) &&
  1626. (psvi->cbFile > 0))
  1627. {
  1628. dwReturn = ERROR_OPERATION_ABORTED;
  1629. }
  1630. else if ((psvi->dwCommand == 0) || (psvi->cbFile == 0))
  1631. {
  1632. /* If thread stopped by itself, need to tell caller to kill it
  1633. * BUT ONLY if the main thread isn't tying to kill off this
  1634. * thread.
  1635. */
  1636. if (InterlockedIncrement(&psvi->lExit) == 0)
  1637. PostMessage(hwndMain, SV_END, 0, 0L);
  1638. InterlockedDecrement( &psvi->lExit );
  1639. }
  1640. }
  1641. else if (psvi->lExit < 0)
  1642. {
  1643. /* If thread stopped by itself, need to tell caller to kill it */
  1644. PostMessage(hwndMain, SV_END, 0, 0L);
  1645. }
  1646. #endif
  1647. return dwReturn;
  1648. }
  1649. #ifdef USETCP
  1650. BOOL
  1651. FHangupConnection(WI *pwi, LPNETDATA lpData)
  1652. {
  1653. if (lpData->SessionNumber != nSessionNone)
  1654. {
  1655. if(lpData->hsd != INVALID_SOCKET)
  1656. {
  1657. closesocket( lpData->hsd );
  1658. lpData->hsd = INVALID_SOCKET;
  1659. }
  1660. lpData->SessionNumber = nSessionNone;
  1661. }
  1662. return FALSE;
  1663. }
  1664. #endif