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.

1839 lines
56 KiB

  1. // Created: Feb '98
  2. // Author : a-rakeba
  3. // History:
  4. // Copyright (C) 1998 Microsoft Corporation
  5. // All rights reserved.
  6. // Microsoft Confidential
  7. extern "C"
  8. {
  9. #include <nt.h>
  10. #include <ntrtl.h>
  11. #include <nturtl.h>
  12. }
  13. #include <CmnHdr.h>
  14. #include <Windows.h>
  15. #include <NtLsApi.h>
  16. #include <LmAccess.h>
  17. #include <LmApiBuf.h>
  18. #include <LmErr.h>
  19. #include <Lm.h>
  20. #include <OleAuto.h>
  21. #include <IpTypes.h>
  22. #ifdef WHISTLER_BUILD
  23. #include "ntverp.h"
  24. #else
  25. #include <SolarVer.h>
  26. #include <PiracyCheck.h>
  27. #endif //WHISTLER_BUILD
  28. #include <Debug.h>
  29. #include <MsgFile.h>
  30. #include <TelnetD.h>
  31. #include <TlntUtils.h>
  32. #include <IoHandlr.h>
  33. #include <Session.h>
  34. #include <killapps.h>
  35. #pragma warning( disable: 4706 )
  36. #define ONE_KB 1024
  37. using namespace _Utils;
  38. using CDebugLevel::TRACE_DEBUGGING;
  39. using CDebugLevel::TRACE_HANDLE;
  40. using CDebugLevel::TRACE_SOCKET;
  41. extern COORD g_coCurPosOnClient;
  42. extern TCHAR g_szHeaderFormat[];
  43. extern HANDLE g_hSyncCloseHandle;
  44. DWORD g_dwPreSessionStateTimeOut = PRE_SESSION_STATE_TIMEOUT;
  45. BOOLEAN IsTheAccount(
  46. LPWSTR pszAccount,
  47. ULONG rid
  48. )
  49. {
  50. SID_NAME_USE sidAccountType;
  51. PSID sid = NULL;
  52. LPWSTR pszDomain = NULL;
  53. DWORD dwSidSize = 0, dwDomainSize = 0;
  54. BOOLEAN fSuccess = FALSE;
  55. if (!LookupAccountNameW(
  56. NULL, // Default to local machine
  57. pszAccount,
  58. NULL,
  59. &dwSidSize,
  60. NULL,
  61. & dwDomainSize,
  62. & sidAccountType
  63. ))
  64. {
  65. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  66. goto AbortIsTheAccount;
  67. }
  68. else
  69. {
  70. // No idea how this can succeed, something fishy
  71. goto AbortIsTheAccount;
  72. }
  73. sid = (PSID) GlobalAlloc(GPTR, dwSidSize);
  74. if (sid)
  75. {
  76. pszDomain = (WCHAR *) GlobalAlloc(GPTR, dwDomainSize * sizeof(WCHAR));
  77. if (pszDomain)
  78. {
  79. if (LookupAccountNameW(
  80. NULL, // Default to local machine
  81. pszAccount,
  82. sid,
  83. &dwSidSize,
  84. pszDomain,
  85. & dwDomainSize,
  86. & sidAccountType
  87. ))
  88. {
  89. PULONG last_sub_authority;
  90. last_sub_authority = RtlSubAuthoritySid(sid, ((*RtlSubAuthorityCountSid(sid)) - 1));
  91. if (*last_sub_authority == rid)
  92. {
  93. fSuccess = TRUE;
  94. }
  95. }
  96. GlobalFree(pszDomain);
  97. }
  98. GlobalFree(sid);
  99. }
  100. AbortIsTheAccount:
  101. return fSuccess;
  102. }
  103. CIoHandler::CIoHandler()
  104. {
  105. m_sSocket = INVALID_SOCKET;
  106. m_hWritePipe = INVALID_HANDLE_VALUE;
  107. m_hReadPipe = INVALID_HANDLE_VALUE;
  108. m_pucReadBuffer = m_ReadFromPipeBuffer;
  109. m_pReadFromSocketBufferCursor = m_ReadFromSocketBuffer;
  110. m_hCredential.dwLower = m_hCredential.dwUpper = 0 ;
  111. InitializeOverlappedStruct( &( m_oReadFromSocket ) );
  112. InitializeOverlappedStruct( &( m_oWriteToSocket ) );
  113. InitializeOverlappedStruct( &( m_oWriteToPipe ) );
  114. InitializeOverlappedStruct( &( m_oReadFromPipe ) );
  115. m_fFirstReadFromPipe = true;
  116. m_fShutDownAfterIO = false;
  117. m_dwWriteToSocketIoLength = 0;
  118. m_dwReadFromPipeIoLength = 0;
  119. m_dwRequestedSize = IPC_HEADER_SIZE;
  120. m_bIpcHeader = true;
  121. m_fLogonUserResult = 0;
  122. m_bNTLMAuthenticated = false;
  123. fDoNTLMAuthFirstTime = true;
  124. m_pspi = NULL;
  125. m_iResult = 0;
  126. m_bOnlyOnce = true;
  127. m_bWaitForEnvOptionOver = false;
  128. m_bInvalidAccount = false;
  129. }
  130. CIoHandler::~CIoHandler()
  131. {
  132. /*++
  133. Close Handles only if they are not already closed.
  134. --*/
  135. TELNET_CLOSE_HANDLE( m_oReadFromSocket.hEvent );
  136. TELNET_CLOSE_HANDLE( m_oWriteToSocket.hEvent );
  137. TELNET_CLOSE_HANDLE( m_oWriteToPipe.hEvent );
  138. TELNET_CLOSE_HANDLE( m_oReadFromPipe.hEvent );
  139. TELNET_CLOSE_HANDLE( m_hWritePipe );
  140. TELNET_CLOSE_HANDLE( m_hReadPipe );
  141. _TRACE( TRACE_DEBUGGING, " ~CIoHandler -- closesocket : %d ", (DWORD)m_sSocket);
  142. if(m_sSocket != INVALID_SOCKET)
  143. {
  144. closesocket( m_sSocket );
  145. m_sSocket = INVALID_SOCKET;
  146. }
  147. _chVERIFY2( !WSACleanup() );
  148. }
  149. void
  150. CIoHandler::Shutdown()
  151. {
  152. _TRACE(TRACE_DEBUGGING, "closing down the session...sending SESSION_EXIT to server");
  153. WriteToServer( SESSION_EXIT, 0, NULL );
  154. //Cancel anyIO pending on handles
  155. CancelIo( m_hReadPipe );
  156. shutdown( m_sSocket, SD_BOTH );
  157. if ( m_bNTLMAuthenticated )
  158. {
  159. DeleteSecurityContext( &m_hContext );
  160. }
  161. if ( m_pSession->m_dwNTLMSetting != NO_NTLM )
  162. {
  163. if( m_hCredential.dwLower != 0 || m_hCredential.dwUpper != 0 )
  164. FreeCredentialsHandle(&m_hCredential);
  165. if( m_pspi != NULL )
  166. FreeContextBuffer( m_pspi );
  167. }
  168. }
  169. bool
  170. CIoHandler::Init ( CSession *pSession )
  171. {
  172. _chASSERT( pSession );
  173. if( !pSession )
  174. {
  175. return( FALSE );
  176. }
  177. m_pSession = pSession ;
  178. m_hReadPipe = GetStdHandle( STD_INPUT_HANDLE );
  179. m_hWritePipe = GetStdHandle( STD_OUTPUT_HANDLE );
  180. if( m_hReadPipe == INVALID_HANDLE_VALUE || m_hWritePipe == INVALID_HANDLE_VALUE)
  181. {
  182. return( FALSE );
  183. }
  184. //The following handles are not to be inherited
  185. _chVERIFY2( SetHandleInformation( m_hReadPipe, HANDLE_FLAG_INHERIT, 0) );
  186. _chVERIFY2( SetHandleInformation( m_hWritePipe, HANDLE_FLAG_INHERIT, 0) );
  187. WSADATA WSAData;
  188. WORD wVersionReqd = MAKEWORD( 2, 0 );
  189. DWORD dwStatus = WSAStartup( wVersionReqd, &WSAData );
  190. if( dwStatus )
  191. {
  192. DecodeSocketStartupErrorCodes( dwStatus ); //It does tracing and logging
  193. return( FALSE );
  194. }
  195. return( TRUE );
  196. }
  197. bool
  198. CIoHandler::WriteToSocket( PUCHAR lpszBuffer, DWORD dwBufSize )
  199. {
  200. DWORD dwNumBytesWritten = 0;
  201. DWORD dwMaxNumBytesToCopy = 0;
  202. if (( (m_dwWriteToSocketIoLength + dwBufSize) >= MAX_WRITE_SOCKET_BUFFER ) ||
  203. //Block until Previous Io is finished
  204. ( !FinishIncompleteIo( ( HANDLE ) m_sSocket, &m_oWriteToSocket, &dwNumBytesWritten ) ))
  205. {
  206. return( FALSE );
  207. }
  208. dwMaxNumBytesToCopy = min(dwBufSize,(MAX_WRITE_SOCKET_BUFFER - m_dwWriteToSocketIoLength - 1 ));
  209. memcpy(m_WriteToSocketBuff + m_dwWriteToSocketIoLength, lpszBuffer,
  210. dwMaxNumBytesToCopy);
  211. m_dwWriteToSocketIoLength += dwMaxNumBytesToCopy;
  212. return( TRUE );
  213. }
  214. //Ignore some keys during authentication.
  215. bool
  216. CIoHandler::RemoveArrowKeysFromBuffer( PDWORD pdwLength,PDWORD pdwOffset)
  217. {
  218. bool bRetVal = false;
  219. DWORD dwLength = *pdwLength;
  220. DWORD dwIndex = (DWORD)(m_pReadFromSocketBufferCursor - m_ReadFromSocketBuffer);
  221. DWORD dwCounter = 0;
  222. DWORD dwInputSequneceState = IP_INIT;
  223. for(dwCounter = 0; dwCounter < dwLength; dwCounter++,dwIndex++)
  224. {
  225. switch( dwInputSequneceState )
  226. {
  227. case IP_INIT:
  228. if (m_ReadFromSocketBuffer[dwIndex] == ESC)
  229. {
  230. dwInputSequneceState = IP_ESC_RCVD;
  231. }
  232. break;
  233. case IP_ESC_RCVD:
  234. if( m_ReadFromSocketBuffer[dwIndex] == '[' )
  235. {
  236. dwInputSequneceState = IP_ESC_BRACKET_RCVD;
  237. }
  238. else
  239. {
  240. dwInputSequneceState = IP_INIT;
  241. }
  242. break;
  243. case IP_ESC_BRACKET_RCVD:
  244. switch( m_ReadFromSocketBuffer[dwIndex] )
  245. {
  246. case 'A':
  247. case 'B':
  248. case 'C':
  249. case 'D':
  250. /*++
  251. You got an escape sequence for arrow keys. Ignore them. Manipulate the buffer length,
  252. Position of cursor in the buffer, and Offset in the buffer accordingly.
  253. --*/
  254. if( (dwLength - (*pdwOffset) - (dwCounter+1) ) > 0)//safety check - don't copy if number of bytes to be copied = 0
  255. {
  256. memcpy( m_pReadFromSocketBufferCursor+dwCounter-2,
  257. m_pReadFromSocketBufferCursor + dwCounter + 1, dwLength - (*pdwOffset) - (dwCounter+1) );
  258. }
  259. *pdwLength -= SIZEOF_ARROWKEY_SEQ;//manipulate bufferlength
  260. bRetVal = true;
  261. break;
  262. default:
  263. break;
  264. }
  265. dwInputSequneceState = IP_INIT;
  266. break;
  267. default:
  268. break;
  269. }
  270. }
  271. return bRetVal;
  272. }
  273. CIoHandler::IO_OPERATIONS
  274. CIoHandler::ProcessCommandLine
  275. (
  276. PDWORD pdwInputLength,
  277. PDWORD pdwOffset,
  278. IO_OPERATIONS ioOpsToPerform
  279. )
  280. {
  281. RemoveArrowKeysFromBuffer( pdwInputLength,pdwOffset);
  282. for( *pdwOffset; *pdwOffset < *pdwInputLength; ( *pdwOffset )++ )
  283. {
  284. switch( *m_pReadFromSocketBufferCursor )
  285. {
  286. case ASCII_DELETE:
  287. case ASCII_BACKSPACE:
  288. // Test if we are at position zero
  289. //second condition (m_pReadFromSocketBufferCursor > m_ReadFromSocketBuffer)
  290. // is guard for excessive ( continuous backspace )
  291. if( *pdwOffset && (m_pReadFromSocketBufferCursor > m_ReadFromSocketBuffer) )
  292. {
  293. /*++
  294. MSRC 678 : Telnet Server Crash/BO with >4300 characters and a backspace
  295. Fix : If a backspace is pressed, we want to write only valid characters starting
  296. from the current offset till the end of valid data in the m_ReadFromSocketBuffer.
  297. --*/
  298. memcpy( m_pReadFromSocketBufferCursor - 1,
  299. m_pReadFromSocketBufferCursor + 1, ((*pdwInputLength)-(*pdwOffset) - 1) );
  300. m_pReadFromSocketBufferCursor--;
  301. ( *pdwInputLength ) -= 2;
  302. (*pdwOffset)--;
  303. UCHAR szTmp[3];
  304. szTmp[0] = ASCII_BACKSPACE;
  305. szTmp[1] = ASCII_SPACE;
  306. szTmp[2] = ASCII_BACKSPACE;
  307. WriteToSocket( szTmp, 3 );
  308. ioOpsToPerform |= WRITE_TO_SOCKET;
  309. }
  310. else
  311. {
  312. memcpy( m_pReadFromSocketBufferCursor,
  313. m_pReadFromSocketBufferCursor + 1, ( *pdwInputLength ) - 1 );
  314. ( *pdwInputLength )--;
  315. }
  316. break;
  317. case ASCII_CARRIAGE:
  318. if( *pdwOffset < *pdwInputLength )
  319. if((*(m_pReadFromSocketBufferCursor + 1 ) == ASCII_LINEFEED) ||
  320. ( *( m_pReadFromSocketBufferCursor + 1 ) == NULL ) )
  321. return ( ioOpsToPerform |= LOGON_COMMAND );
  322. m_pReadFromSocketBufferCursor++;
  323. break;
  324. case NULL:
  325. case ASCII_LINEFEED:
  326. if( *pdwOffset )
  327. if( *( m_pReadFromSocketBufferCursor - 1 ) == ASCII_CARRIAGE )
  328. return ( ioOpsToPerform |= LOGON_COMMAND );
  329. m_pReadFromSocketBufferCursor++;
  330. break;
  331. default:
  332. if( m_pSession->CRFCProtocol::m_fPasswordConcealMode )
  333. {
  334. // This results in more than one * being output for things like up-arrow, so don't do it
  335. //UCHAR szTmp[1];
  336. //szTmp[0] = '*';
  337. //WriteToSocket( szTmp, 1 );
  338. }
  339. else
  340. {
  341. UCHAR szTmp[1];
  342. szTmp[0] = *m_pReadFromSocketBufferCursor;
  343. WriteToSocket( szTmp, 1 );
  344. }
  345. ioOpsToPerform |= WRITE_TO_SOCKET;
  346. m_pReadFromSocketBufferCursor++;
  347. break;
  348. }
  349. }
  350. return ( ioOpsToPerform );
  351. }
  352. CIoHandler::IO_OPERATIONS
  353. CIoHandler::ProcessAuthenticationLine (
  354. PDWORD pdwInputLength,
  355. PDWORD pdwOffset,
  356. IO_OPERATIONS ioOpsToPerform
  357. )
  358. {
  359. CHAR szMessageBuffer[ONE_KB + 1];
  360. DWORD dwMessageLength;
  361. PUCHAR pEndLine;
  362. DWORD dwLineLength = 0;
  363. CHAR szTmp[ONE_KB];
  364. LPVOID lpMsgBuf = NULL;
  365. LPVOID lpTemp = NULL;
  366. // Initialize Variables
  367. szMessageBuffer[0] = 0;
  368. if( !m_pSession->CRFCProtocol::m_bIsUserNameProvided )
  369. {
  370. pEndLine = (PUCHAR) memchr( m_ReadFromSocketBuffer, '\r', *pdwInputLength);
  371. if( !pEndLine )
  372. return ( ioOpsToPerform );
  373. ( *pEndLine ) = 0;
  374. dwLineLength = (DWORD)(pEndLine - m_ReadFromSocketBuffer + 2);
  375. }
  376. switch( m_SocketControlState )
  377. {
  378. case STATE_AUTH_NAME:
  379. if( !m_pSession->CRFCProtocol::m_bIsUserNameProvided )
  380. {
  381. strncpy( m_pSession->CSession::m_pszUserName,
  382. ( PCHAR ) m_ReadFromSocketBuffer,
  383. (dwLineLength > MAX_PATH) ? MAX_PATH : dwLineLength );
  384. m_pSession->CSession::m_pszUserName[MAX_PATH] = '\0';
  385. }
  386. else
  387. {
  388. //Use the -l user name only once.
  389. m_pSession->CRFCProtocol::m_bIsUserNameProvided = false;
  390. }
  391. m_bInvalidAccount = false;
  392. switch(ParseAndValidateAccount())
  393. {
  394. case PVA_INVALIDACCOUNT:
  395. m_bInvalidAccount = true; // Fall through to take the password, no break ...
  396. case PVA_SUCCESS:
  397. g_coCurPosOnClient.Y++; //Hack. needed for keeping track of rows for VTNT and stream
  398. lstrcpyA( szMessageBuffer, PASS_REQUEST );
  399. m_pSession->CRFCProtocol::m_fPasswordConcealMode = true;
  400. m_SocketControlState = STATE_AUTH_PASSWORD;
  401. break;
  402. case PVA_NODATA:
  403. g_coCurPosOnClient.Y++; //Hack. needed for keeping track of rows for VTNT and stream
  404. lstrcatA( szMessageBuffer, LOGIN_REQUEST );
  405. break;
  406. case PVA_BADFORMAT:
  407. g_coCurPosOnClient.Y += 3; //Hack. needed for keeping track of rows for VTNT and stream
  408. lstrcatA( szMessageBuffer, BAD_USERNAME_STR );
  409. lstrcatA( szMessageBuffer, LOGIN_REQUEST );
  410. break;
  411. case PVA_GUEST:
  412. g_coCurPosOnClient.Y += 3; //Hack. needed for keeping track of rows for VTNT and stream
  413. lstrcatA( szMessageBuffer, NO_GUEST_STR );
  414. lstrcatA( szMessageBuffer, LOGIN_REQUEST );
  415. break;
  416. default: // PVA_OTHERERROR as of now and any other unless a handler is added above ...
  417. goto AbortProcessAuthenticationLine;
  418. }
  419. break;
  420. case STATE_AUTH_PASSWORD:
  421. strncpy( m_pSession->CSession::m_pszPassword,
  422. ( PCHAR ) m_ReadFromSocketBuffer,
  423. (dwLineLength > MAX_PATH) ? MAX_PATH : dwLineLength );
  424. BOOL fResult;
  425. fResult = m_bInvalidAccount ? false : AuthenticateUser();
  426. if(fResult)
  427. {
  428. // Authentication was success so we proceed to license
  429. // verification
  430. m_SocketControlState = STATE_CHECK_LICENSE;
  431. }
  432. else
  433. {
  434. DWORD dwError = GetLastError();
  435. int iRet = 0;
  436. if( dwError == ERROR_FILENAME_EXCED_RANGE || m_bInvalidAccount)
  437. {
  438. dwError = ERROR_LOGON_FAILURE;
  439. }
  440. //
  441. // If not Japanese codepage (932) then use LANG_NEUTRAL to retrieve
  442. // system error message in host language. For Japanese, the
  443. // error must be in English because they have different codesets
  444. // and encodings and we cannot know what codeset the client is
  445. // running.
  446. //
  447. if( GetACP() != 932 )
  448. {
  449. FormatMessageA(
  450. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  451. NULL, dwError,
  452. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
  453. ( LPSTR ) &lpTemp, 0, NULL );
  454. if(!lpTemp)
  455. {
  456. goto Error;
  457. }
  458. lpMsgBuf = (LPSTR) LocalAlloc(LPTR,strlen((LPSTR)lpTemp)+1);
  459. if(!lpMsgBuf)
  460. {
  461. goto Error;
  462. }
  463. if(!CharToOemA((LPCSTR)lpTemp,(LPSTR)lpMsgBuf))
  464. {
  465. goto Error;
  466. }
  467. }
  468. else
  469. {
  470. FormatMessageA(
  471. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  472. NULL, dwError,
  473. MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
  474. (LPSTR)&lpMsgBuf, 0, NULL );
  475. }
  476. if( !lpMsgBuf )
  477. {
  478. goto Error;
  479. }
  480. if (_snprintf( szMessageBuffer, ONE_KB, "\r\n%s", lpMsgBuf ) < 0)
  481. {
  482. szMessageBuffer[ONE_KB] = '\0';
  483. }
  484. m_pSession->CRFCProtocol::m_fPasswordConcealMode = false;
  485. if( ( ++( m_pSession->CSession::m_wNumFailedLogins ) ) <
  486. m_pSession->m_dwMaxFailedLogins )
  487. {
  488. g_coCurPosOnClient.Y += 5; //Hack. needed for keeping track of rows for VTNT nd stream
  489. if (_snprintf(
  490. szMessageBuffer + strlen( szMessageBuffer ),
  491. ONE_KB - strlen(szMessageBuffer),
  492. "%s%s",
  493. LOGIN_FAIL,
  494. LOGIN_REQUEST
  495. ) < 0)
  496. {
  497. szMessageBuffer[ONE_KB] = '\0';
  498. }
  499. m_SocketControlState = STATE_AUTH_NAME;
  500. }
  501. else
  502. {
  503. if (_snprintf(
  504. szMessageBuffer + strlen( szMessageBuffer ),
  505. ONE_KB - strlen(szMessageBuffer),
  506. "%s%s",
  507. LOGIN_FAIL,
  508. TERMINATE
  509. ) < 0)
  510. {
  511. szMessageBuffer[ONE_KB] = '\0';
  512. }
  513. m_SocketControlState = STATE_TERMINATE;
  514. CIoHandler::m_fShutDownAfterIO = true;
  515. }
  516. }
  517. #ifdef LOGGING_ENABLED
  518. if( !fResult )
  519. {
  520. m_pSession->LogIfOpted( FAIL, LOGON );
  521. }
  522. #endif
  523. Error:
  524. if(lpMsgBuf)
  525. {
  526. LocalFree( lpMsgBuf );
  527. lpMsgBuf = NULL;
  528. }
  529. if(lpTemp)
  530. {
  531. LocalFree(lpTemp);
  532. lpTemp = NULL;
  533. }
  534. break;
  535. default:
  536. strncpy( szMessageBuffer, "\r\n", (ONE_KB -1)); // NO BO attack here - Baskar
  537. break;
  538. }
  539. //
  540. // Remove Line From Read Socket buffer if there is more IO
  541. //
  542. if( dwLineLength < *pdwInputLength )
  543. {
  544. ( *pdwInputLength ) -= dwLineLength;
  545. memcpy( m_ReadFromSocketBuffer, m_ReadFromSocketBuffer + dwLineLength,
  546. ( *pdwInputLength ) );
  547. ioOpsToPerform |= LOGON_DATA_UNFINISHED;
  548. }
  549. ( *pdwOffset ) = 0;
  550. m_pReadFromSocketBufferCursor = m_ReadFromSocketBuffer;
  551. //
  552. // Send notification string; if required
  553. //
  554. dwMessageLength = strlen( szMessageBuffer );
  555. WriteToSocket( (PUCHAR)szMessageBuffer, dwMessageLength);
  556. ioOpsToPerform |= WRITE_TO_SOCKET;
  557. AbortProcessAuthenticationLine:
  558. if(lpMsgBuf)
  559. {
  560. LocalFree( lpMsgBuf );
  561. lpMsgBuf = NULL;
  562. }
  563. if(lpTemp)
  564. {
  565. LocalFree(lpTemp);
  566. lpTemp = NULL;
  567. }
  568. return ( ioOpsToPerform );
  569. }
  570. int CIoHandler::ParseAndValidateAccount()
  571. {
  572. CHAR *pPos=NULL;
  573. int nRet = PVA_OTHERERROR;
  574. bool bDefaultDomain = true;
  575. WCHAR lpszDomainOfMac[MAX_DOMAIN_NAME_LEN + 1];
  576. int iRetVal = PVA_OTHERERROR;
  577. BOOLEAN bIsGuest = FALSE;
  578. LPWSTR lpszJoinedDomain = NULL; // Will be allocated by NetGetJoin...
  579. int iStatus = 0;
  580. LPWSTR lpwszUserNDomain = NULL;
  581. DWORD dwSize = 0;
  582. if(m_pSession->CSession::m_pszUserName[0] == 0)
  583. return PVA_NODATA;
  584. m_pSession->CSession::m_szUser[0] = L'\0';
  585. // Copy the default domain initially, if the user has supplied a domain, then use it
  586. wcsncpy(m_pSession->CSession::m_szDomain, m_pSession->CSession::m_pszDefaultDomain, MAX_DOMAIN_NAME_LEN);
  587. m_pSession->CSession::m_szDomain[MAX_DOMAIN_NAME_LEN] = L'\0';
  588. ConvertSChartoWChar(m_pSession->CSession::m_pszUserName, m_pSession->CSession::m_szUser);
  589. // User parsing and validity checks
  590. if((pPos = strchr(m_pSession->CSession::m_pszUserName, '\\')))
  591. {
  592. if(pPos == m_pSession->CSession::m_pszUserName)
  593. return PVA_BADFORMAT;
  594. if(strchr(pPos+1, '\\'))
  595. return PVA_BADFORMAT;
  596. *pPos++ = '\0';
  597. if (*pPos == '\0')
  598. return PVA_BADFORMAT;
  599. bDefaultDomain = false;
  600. strcpy(m_pSession->CSession::m_pszDomain, m_pSession->CSession::m_pszUserName);
  601. strcpy(m_pSession->CSession::m_pszUserName, pPos);
  602. ConvertSChartoWChar(m_pSession->CSession::m_pszUserName, m_pSession->CSession::m_szUser);
  603. ConvertSChartoWChar(m_pSession->CSession::m_pszDomain, m_pSession->CSession::m_szDomain);
  604. }
  605. if (! GetDomainHostedByThisMc(lpszDomainOfMac))
  606. {
  607. iRetVal = PVA_OTHERERROR;
  608. goto End;
  609. }
  610. // Domain validity checks
  611. if((_wcsicmp(m_pSession->CSession::m_szDomain, L".") == 0) ||
  612. (_wcsicmp(m_pSession->CSession::m_szDomain, L"localhost") == 0) ||
  613. (_wcsicmp(m_pSession->CSession::m_szDomain, lpszDomainOfMac) == 0))
  614. {
  615. wcscpy(m_pSession->CSession::m_szDomain, lpszDomainOfMac);
  616. }
  617. else if(!m_pSession->m_dwAllowTrustedDomain) // If not local machine, then check for domain trusts
  618. {
  619. /*
  620. If AllowTrustedDomain is 0 then
  621. check if the domain is same as the domain hosted by this machine
  622. or same as the domain to which this machine is joined
  623. If yes proceed
  624. If not,
  625. if the domain we got is from default domain setting
  626. (user has not typed the domain name), then fall back to the local
  627. machine
  628. else
  629. bail out
  630. If the machine is joined to a workgroup instead of a domain, then the fall back should
  631. be to the domain hosted by this machine.
  632. */
  633. // NetGetJoinInformation is unfortunately not available in versions prior to w2k, so check whether it is available
  634. {
  635. HMODULE dll = NULL;
  636. FARPROC proc = NULL;
  637. TCHAR szDllPath[MAX_PATH*2] = { 0 };
  638. UINT iRet = 0;
  639. typedef NET_API_STATUS
  640. (NET_API_FUNCTION *OUR_NET_GET_JOIN_INFORMATION)(
  641. IN LPCWSTR lpServer OPTIONAL,
  642. OUT LPWSTR *lpNameBuffer,
  643. OUT PNETSETUP_JOIN_STATUS BufferType
  644. );
  645. BOOL net_api_found = FALSE;
  646. iRet = GetSystemDirectory(szDllPath,(MAX_PATH*2)-1);
  647. if(iRet == 0 || iRet >= (MAX_PATH*2))
  648. {
  649. iRetVal = PVA_OTHERERROR;
  650. goto End;
  651. }
  652. _tcsncpy(szDllPath+iRet,TEXT("\\NETAPI32.DLL"),(MAX_PATH*2)-iRet-1);
  653. dll = LoadLibrary(szDllPath);
  654. if (! dll)
  655. {
  656. iRetVal = PVA_OTHERERROR;
  657. goto End;
  658. }
  659. proc = GetProcAddress(dll, "NetGetJoinInformation");
  660. if (proc )
  661. {
  662. NETSETUP_JOIN_STATUS dwStatus;
  663. if (NERR_Success == (*((OUR_NET_GET_JOIN_INFORMATION)proc))(NULL, &lpszJoinedDomain, &dwStatus))
  664. {
  665. if (dwStatus != NetSetupDomainName) // Not joined to a domain
  666. {
  667. NetApiBufferFree(lpszJoinedDomain);
  668. lpszJoinedDomain = NULL;
  669. }
  670. net_api_found = TRUE;
  671. }
  672. else
  673. {
  674. lpszJoinedDomain = NULL;
  675. }
  676. }
  677. else
  678. {
  679. HKEY win_logon;
  680. LONG error;
  681. DWORD needed = 0, value_type = REG_SZ;
  682. error = RegOpenKeyEx(
  683. HKEY_LOCAL_MACHINE,
  684. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  685. 0, // Reserved
  686. KEY_QUERY_VALUE | MAXIMUM_ALLOWED,
  687. &win_logon
  688. );
  689. if (error == ERROR_SUCCESS)
  690. {
  691. RegQueryValueExW(win_logon, L"CachePrimaryDomain", 0, &value_type, NULL, &needed); // This will return the size
  692. lpszJoinedDomain = (WCHAR *)GlobalAlloc(GPTR, needed);
  693. if (lpszJoinedDomain)
  694. {
  695. if (ERROR_SUCCESS != RegQueryValueExW(win_logon, L"CachePrimaryDomain", 0, &value_type, (LPBYTE)lpszJoinedDomain, &needed))
  696. {
  697. GlobalFree(lpszJoinedDomain);
  698. lpszJoinedDomain = NULL;
  699. }
  700. }
  701. RegCloseKey(win_logon);
  702. }
  703. }
  704. if (lpszJoinedDomain && (_wcsicmp(m_pSession->CSession::m_szDomain, lpszJoinedDomain) == 0))
  705. {
  706. ; // Nothing to do here the account is from a valid domain
  707. }
  708. else
  709. {
  710. if (bDefaultDomain) wcscpy(m_pSession->CSession::m_szDomain, lpszDomainOfMac);
  711. else m_bInvalidAccount = true;
  712. }
  713. if (lpszJoinedDomain)
  714. {
  715. if (net_api_found)
  716. {
  717. NetApiBufferFree(lpszJoinedDomain);
  718. }
  719. else
  720. {
  721. GlobalFree(lpszJoinedDomain);
  722. }
  723. }
  724. }
  725. if (m_bInvalidAccount) return PVA_INVALIDACCOUNT;
  726. }
  727. dwSize = wcslen(m_pSession->CSession::m_szDomain) +
  728. wcslen(m_pSession->CSession::m_szUser) + 2;
  729. lpwszUserNDomain = new WCHAR[dwSize]; // 2 for '\\' and '\0'
  730. if (!lpwszUserNDomain)
  731. {
  732. iRetVal = PVA_NOMEMORY;
  733. goto End;
  734. }
  735. _snwprintf(lpwszUserNDomain,dwSize -1,L"%s\\%s",m_pSession->CSession::m_szDomain,m_pSession->CSession::m_szUser);
  736. lpwszUserNDomain[dwSize -1] = L'\0';
  737. bIsGuest = IsTheAccount(lpwszUserNDomain, DOMAIN_USER_RID_GUEST);
  738. _chVERIFY2( iStatus = WideCharToMultiByte( GetConsoleCP(), 0, m_pSession->CSession::m_szDomain,
  739. -1, m_pSession->m_pszDomain, MAX_PATH , NULL, NULL ) );
  740. _TRACE(TRACE_DEBUGGING,"Domain:%s",m_pSession->m_pszDomain);
  741. delete[] lpwszUserNDomain;
  742. return bIsGuest ? PVA_GUEST : PVA_SUCCESS;
  743. End:
  744. m_pSession->CSession::m_szDomain[0] = L'\0';
  745. m_pSession->CSession::m_szUser[0] = L'\0';
  746. //PREFIX reports error - leaking memory. But we are correctly freeing all the memory. Won't fix.
  747. return iRetVal;
  748. }
  749. int
  750. CIoHandler::AuthenticateUser( void )
  751. {
  752. LPWSTR szPassWd = NULL;
  753. ConvertSChartoWChar( m_pSession->CSession::m_pszPassword, &szPassWd );
  754. /* when LogonUserA is given user name etc as per code page differen from
  755. * 1252, it was not succeding. May be the conversion from say 850 to
  756. * unicode is not happening. It is assuming The i/p is as per 1252.
  757. * Is it possible?
  758. * So, Converting everything to UNICODE */
  759. m_fLogonUserResult = LogonUser( m_pSession->CSession::m_szUser,
  760. m_pSession->CSession::m_szDomain, szPassWd,
  761. LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
  762. &(m_pSession->CSession::m_hToken) ) ;
  763. SfuZeroMemory(szPassWd, sizeof(WCHAR)*lstrlenW(szPassWd));
  764. delete[] szPassWd;
  765. //scratch out the password
  766. SfuZeroMemory( m_pSession->CSession::m_pszPassword,
  767. strlen( m_pSession->CSession::m_pszPassword ));
  768. if (m_pSession->CSession::m_szUser[0]!= L'\0')
  769. {
  770. SfuZeroMemory( m_pSession->CSession::m_szUser,
  771. wcslen( m_pSession->CSession::m_szUser)*sizeof(WCHAR));
  772. }
  773. return ( m_fLogonUserResult );
  774. }
  775. //When this message is received by the server, it will check for license
  776. //and replies
  777. bool
  778. CIoHandler::SendDetailsAndAskForLicense()
  779. {
  780. bool bRetVal = true;
  781. if( !GetAuthenticationId( m_pSession->CSession::m_hToken,
  782. &m_pSession->CSession::m_AuthenticationId ) )
  783. {
  784. return ( FALSE );
  785. }
  786. //GetUserName(); //For NTLM
  787. DWORD dwDomainLength = strlen( m_pSession->m_pszDomain ) + 1;
  788. DWORD dwUserLength = strlen( m_pSession->m_pszUserName ) + 1;
  789. DWORD dwPeerLength = strlen( m_pSession->m_szPeerHostName ) + 1;
  790. DWORD dwAuthIdLength = sizeof( m_pSession->m_AuthenticationId );
  791. DWORD dwTotal = dwDomainLength + dwUserLength + dwPeerLength +
  792. dwAuthIdLength;
  793. UCHAR *lpData = NULL;
  794. UCHAR *lpPtrData = NULL;
  795. lpData = new UCHAR[ IPC_HEADER_SIZE + dwTotal ];
  796. if( !lpData )
  797. {
  798. return ( FALSE );
  799. }
  800. lpPtrData = lpData;
  801. lpPtrData[ 0 ] = SESSION_DETAILS;
  802. lpPtrData++;
  803. memcpy( lpPtrData, &dwTotal, sizeof( DWORD ) );
  804. lpPtrData += sizeof( DWORD );
  805. memcpy( lpPtrData, m_pSession->m_pszDomain, dwDomainLength );
  806. lpPtrData += dwDomainLength;
  807. memcpy( lpPtrData, m_pSession->m_pszUserName, dwUserLength );
  808. lpPtrData += dwUserLength;
  809. memcpy( lpPtrData, m_pSession->m_szPeerHostName, dwPeerLength );
  810. lpPtrData += dwPeerLength;
  811. memcpy( lpPtrData, &( m_pSession->m_AuthenticationId ), dwAuthIdLength );
  812. dwTotal += IPC_HEADER_SIZE;
  813. //As a response to this server indicates the availability of License
  814. bRetVal = WriteToServer( SESSION_DETAILS, dwTotal, lpData );
  815. delete[] lpData;
  816. return( bRetVal );
  817. }
  818. int
  819. CIoHandler::CheckLicense()
  820. {
  821. bool fIsAdmin = false;
  822. bool fIsMemberOfTelnetClients = false;
  823. if( !( m_pSession->CheckGroupMembership( &fIsAdmin,
  824. &fIsMemberOfTelnetClients ) ) )
  825. {
  826. return ( FALSE );
  827. }
  828. if( !fIsAdmin && !fIsMemberOfTelnetClients )
  829. {
  830. return ( NOT_MEMBER_OF_TELNETCLIENTS_GROUP );
  831. }
  832. if( !SendDetailsAndAskForLicense() )
  833. {
  834. return( FALSE );
  835. }
  836. return( WAIT_FOR_SERVER_REPLY );
  837. }
  838. /*++
  839. Sends a termination string to the client.
  840. --*/
  841. void
  842. CIoHandler::SendTerminateString(char *pszMessageBuffer)
  843. {
  844. m_SocketControlState = STATE_TERMINATE;
  845. CIoHandler::m_fShutDownAfterIO = true;
  846. WriteToSocket( ( PUCHAR ) pszMessageBuffer, strlen( pszMessageBuffer ) );
  847. }
  848. #define HALF_K 512
  849. bool
  850. CIoHandler::IsTimedOut ( )
  851. {
  852. //because we entered this function, we already know that we are not
  853. //in STATE_SESSION. the next block of code checks whether more than
  854. //PRE_SESSION_STATE_TIMEOUT seconds has elapsed since the telnet client
  855. //first connected to us. if so, we deem that the client was given enough
  856. //time for 1) reasonable negotiation, 2) entering name & password, but
  857. //STATE_SESSION was not reached.
  858. if (0 == g_dwPreSessionStateTimeOut)
  859. {
  860. return false;
  861. }
  862. char szMessageBuffer[HALF_K + 1];
  863. if (_snprintf( szMessageBuffer, HALF_K, "\r\n%s\r\n%s", TIMEOUT_STR, TERMINATE ) < 0)
  864. {
  865. szMessageBuffer[HALF_K] = '\0';
  866. }
  867. if( GetTickCount() - m_pSession->CSession::m_dwTickCountAtLogon >
  868. g_dwPreSessionStateTimeOut )
  869. {
  870. SendTerminateString(szMessageBuffer);
  871. return ( true );
  872. }
  873. return( false );
  874. }
  875. CIoHandler::IO_OPERATIONS
  876. CIoHandler::ProcessDataFromSocket ( DWORD dwIoSize )
  877. {
  878. char szMessageBuffer[HALF_K + 1];
  879. IO_OPERATIONS ioOpsToPerform = 0;
  880. DWORD dwCurrentOffset;
  881. DWORD dwInputLength;
  882. bool bContinue;
  883. // Initialize Data
  884. dwCurrentOffset = (DWORD)(m_pReadFromSocketBufferCursor - m_ReadFromSocketBuffer);
  885. dwInputLength = dwIoSize + dwCurrentOffset;
  886. if(dwInputLength >= sizeof( m_ReadFromSocketBuffer ) )
  887. {
  888. /*++
  889. MSRC 678 : Telnet Server Crash/BO with >4300 characters and a backspace.
  890. Fix : If Input length reaches it's limit, we terminate the session giving a message :
  891. The Input Line is too long.
  892. --*/
  893. if (_snprintf( szMessageBuffer, HALF_K, "\r\n%s",LONG_SESSION_DATA) < 0)
  894. {
  895. szMessageBuffer[HALF_K] = '\0';
  896. }
  897. SendTerminateString(szMessageBuffer);
  898. ioOpsToPerform |= WRITE_TO_SOCKET;
  899. return ( ioOpsToPerform );
  900. }
  901. m_ReadFromSocketBuffer[ dwInputLength ] = '\0';
  902. ioOpsToPerform = READ_FROM_SOCKET;
  903. if( IsTimedOut() )
  904. {
  905. ioOpsToPerform |= WRITE_TO_SOCKET;
  906. return ( ioOpsToPerform );
  907. }
  908. do {
  909. // we break unless someone is sure that we should continue.
  910. bContinue = false;
  911. switch ( m_SocketControlState )
  912. {
  913. case STATE_INIT:
  914. // we are not in a position to consume anything yet, so
  915. // make sure we save the stuff for later on !!
  916. dwCurrentOffset = dwInputLength;
  917. m_pReadFromSocketBufferCursor += dwIoSize;
  918. break;
  919. case STATE_NTLMAUTH:
  920. break;
  921. case STATE_CHECK_LICENSE:
  922. m_iResult = CheckLicense();
  923. m_SocketControlState = STATE_LICENSE_AVAILABILITY_KNOWN;
  924. if( m_iResult == FALSE )
  925. {
  926. m_iResult = DENY_LICENSE;
  927. }
  928. else if ( m_iResult == WAIT_FOR_SERVER_REPLY )
  929. {
  930. do
  931. {
  932. //We will have to get a reply from server regarding license
  933. TlntSynchronizeOn(m_oReadFromPipe.hEvent);
  934. OnReadFromPipeCompletion();
  935. }
  936. while( m_iResult == WAIT_FOR_SERVER_REPLY );
  937. }
  938. bContinue = true;
  939. break;
  940. case STATE_LICENSE_AVAILABILITY_KNOWN:
  941. if( m_iResult != ISSUE_LICENSE )
  942. {
  943. //We should not log at the time of logging off.
  944. m_pSession->m_fLogonUserResult = 0;
  945. }
  946. if( m_iResult )
  947. {
  948. switch( m_iResult ) {
  949. case ISSUE_LICENSE:
  950. szMessageBuffer[0] = 0;
  951. m_pSession->CRFCProtocol::m_fPasswordConcealMode = false;
  952. m_SocketControlState = STATE_VTERM_INIT_NEGO;
  953. bContinue = true;
  954. #ifdef LOGGING_ENABLED
  955. m_pSession->LogIfOpted( SUCCESS, LOGON );
  956. #endif
  957. break;
  958. #if BETA
  959. case LICENSE_EXPIRED:
  960. m_pSession->CRFCProtocol::m_fPasswordConcealMode = false;
  961. if (_snprintf( szMessageBuffer, HALF_K, "%s%s", LICENSE_EXPIRED_STR,
  962. TERMINATE ) < 0)
  963. {
  964. szMessageBuffer[HALF_K] = '\0';
  965. }
  966. m_SocketControlState = STATE_TERMINATE;
  967. CIoHandler::m_fShutDownAfterIO = true;
  968. break;
  969. #endif
  970. case NOT_MEMBER_OF_TELNETCLIENTS_GROUP:
  971. m_pSession->CRFCProtocol::m_fPasswordConcealMode = false;
  972. if (_snprintf( szMessageBuffer, HALF_K, "%s%s",
  973. NOT_MEMBER_OF_TELNETCLIENTS_GROUP_STR, TERMINATE) < 0)
  974. {
  975. szMessageBuffer[HALF_K] = '\0';
  976. }
  977. m_SocketControlState = STATE_TERMINATE;
  978. CIoHandler::m_fShutDownAfterIO = true;
  979. break;
  980. case DENY_LICENSE:
  981. szMessageBuffer[0] = 0;
  982. m_pSession->CRFCProtocol::m_fPasswordConcealMode = false;
  983. m_SocketControlState = STATE_TERMINATE;
  984. CIoHandler::m_fShutDownAfterIO = true;
  985. break;
  986. }
  987. if ( *szMessageBuffer )
  988. {
  989. WriteToSocket((PUCHAR)szMessageBuffer, strlen(szMessageBuffer));
  990. ioOpsToPerform |= WRITE_TO_SOCKET ;
  991. }
  992. }
  993. break;
  994. case STATE_VTERM_INIT_NEGO:
  995. {
  996. // kick off the term type negotiation.
  997. // Term Type negotiation happens after login for several reasons.
  998. int nBytesToWrite = 0;
  999. m_SocketControlState = STATE_VTERM;
  1000. // Some clients are proactive and send us WILL TERMTYPE, in that
  1001. // case we already know the Client can do term type and we start
  1002. // the subnegotiation. else we ask if start the whole termtype process.
  1003. if ( m_pSession->CRFCProtocol::m_remoteOptions[ TO_TERMTYPE ] )
  1004. {
  1005. DO_TERMTYPE_SUB_NE( szMessageBuffer );
  1006. nBytesToWrite = 6;
  1007. }
  1008. else
  1009. {
  1010. m_pSession->CRFCProtocol::m_fWaitingForResponseToA_DO_ForTO_TERMTYPE = true;
  1011. DO_OPTION( szMessageBuffer, TO_TERMTYPE );
  1012. nBytesToWrite = 3;
  1013. }
  1014. WriteToSocket((PUCHAR)szMessageBuffer, nBytesToWrite);
  1015. ioOpsToPerform |= WRITE_TO_SOCKET ;
  1016. }
  1017. break;
  1018. case STATE_VTERM:
  1019. // We Wait here until we know what term type to use. This is a
  1020. // no return point - after this the User can't change the term type.
  1021. if( m_pSession->CSession::m_bNegotiatedTermType )
  1022. {
  1023. m_SocketControlState = STATE_SESSION;
  1024. if( !m_pSession->CShell::StartUserSession( ) )
  1025. {
  1026. m_SocketControlState = STATE_TERMINATE;
  1027. CIoHandler::m_fShutDownAfterIO = true;
  1028. if (_snprintf( szMessageBuffer, HALF_K, "%s%s", SESSION_INIT_FAIL,
  1029. TERMINATE) < 0)
  1030. {
  1031. szMessageBuffer[HALF_K] = '\0';
  1032. }
  1033. WriteToSocket((PUCHAR)szMessageBuffer,
  1034. strlen( szMessageBuffer ) );
  1035. ioOpsToPerform |= WRITE_TO_SOCKET ;
  1036. }
  1037. m_pSession->FreeInitialVariables();
  1038. }
  1039. break;
  1040. case STATE_BANNER_FOR_AUTH:
  1041. CHAR szTmp[ MAX_PATH + 1];
  1042. strncpy(szTmp, LOGIN_BANNER, MAX_PATH);
  1043. szTmp[MAX_PATH] = '\0';
  1044. WriteToSocket( ( PUCHAR )szTmp, strlen( szTmp ) );
  1045. ioOpsToPerform |= WRITE_TO_SOCKET ;
  1046. m_SocketControlState = STATE_WAIT_FOR_ENV_OPTION;
  1047. bContinue = true;
  1048. break;
  1049. case STATE_WAIT_FOR_ENV_OPTION:
  1050. if( m_bWaitForEnvOptionOver )
  1051. {
  1052. m_SocketControlState = STATE_LOGIN_PROMPT;
  1053. bContinue = true;
  1054. }
  1055. break;
  1056. case STATE_LOGIN_PROMPT:
  1057. if( !m_pSession->CRFCProtocol::m_bIsUserNameProvided && m_bOnlyOnce )
  1058. {
  1059. m_bOnlyOnce = false;
  1060. WriteToSocket( ( PUCHAR )LOGIN_REQUEST, strlen( LOGIN_REQUEST ) );
  1061. ioOpsToPerform |= WRITE_TO_SOCKET ;
  1062. }
  1063. m_SocketControlState = STATE_AUTH_NAME;
  1064. case STATE_AUTH_NAME: //fall thru
  1065. case STATE_AUTH_PASSWORD:
  1066. do
  1067. {
  1068. // Processing of Command Input
  1069. if( ioOpsToPerform & LOGON_DATA_UNFINISHED )
  1070. ioOpsToPerform ^= LOGON_DATA_UNFINISHED;
  1071. ioOpsToPerform = ProcessCommandLine( &dwInputLength,
  1072. &dwCurrentOffset, ioOpsToPerform );
  1073. if( m_pSession->CRFCProtocol::m_bIsUserNameProvided )
  1074. {
  1075. ioOpsToPerform |= LOGON_COMMAND;
  1076. }
  1077. // If there is a completed command line; deal with it
  1078. if( ioOpsToPerform & LOGON_COMMAND )
  1079. {
  1080. ioOpsToPerform = ProcessAuthenticationLine( &dwInputLength,
  1081. &dwCurrentOffset, ioOpsToPerform );
  1082. ioOpsToPerform ^= LOGON_COMMAND;
  1083. }
  1084. } while( ioOpsToPerform & LOGON_DATA_UNFINISHED );
  1085. if ( m_SocketControlState != STATE_AUTH_NAME &&
  1086. m_SocketControlState != STATE_AUTH_PASSWORD )
  1087. {
  1088. bContinue = true;
  1089. }
  1090. break;
  1091. default:
  1092. break;
  1093. }
  1094. } while ( bContinue );
  1095. return ( ioOpsToPerform );
  1096. }
  1097. bool
  1098. CIoHandler::ProcessUserDataReadFromSocket ( DWORD dwIoSize )
  1099. {
  1100. DWORD dwCurrentOffset;
  1101. DWORD dwInputLength;
  1102. if( _strcmpi( m_pSession->m_pszTermType, "VTNT" ) != 0 )
  1103. {
  1104. dwCurrentOffset = (DWORD)(m_pReadFromSocketBufferCursor- m_ReadFromSocketBuffer);
  1105. dwInputLength = dwIoSize + dwCurrentOffset;
  1106. if(dwInputLength >= sizeof( m_ReadFromSocketBuffer ) )
  1107. {
  1108. dwInputLength = sizeof( m_ReadFromSocketBuffer ) - 1;
  1109. }
  1110. m_ReadFromSocketBuffer[ dwInputLength ] = '\0';
  1111. m_pReadFromSocketBufferCursor = m_ReadFromSocketBuffer;
  1112. if( dwIoSize >= sizeof( m_ReadFromSocketBuffer ) )
  1113. {
  1114. dwIoSize = sizeof( m_ReadFromSocketBuffer ) -1;
  1115. }
  1116. m_ReadFromSocketBuffer[ dwIoSize ] = '\0';
  1117. }
  1118. if( !m_pSession->CScraper::EmulateAndWriteToCmdConsoleInput() )
  1119. {
  1120. return( FALSE );
  1121. }
  1122. return ( TRUE );
  1123. }
  1124. CIoHandler::IO_OPERATIONS
  1125. CIoHandler::OnDataFromSocket ( )
  1126. {
  1127. IO_OPERATIONS ioOpsToPerform1 = 0;
  1128. IO_OPERATIONS ioOpsToPerform2 = 0;
  1129. // filter the data at the RFCProtocol handler
  1130. ioOpsToPerform1 = m_pSession->CRFCProtocol::
  1131. ProcessDataReceivedOnSocket( &m_dwReadFromSocketIoLength );
  1132. if( m_SocketControlState != STATE_SESSION )
  1133. {
  1134. ioOpsToPerform2 = ProcessDataFromSocket( m_dwReadFromSocketIoLength );
  1135. }
  1136. else
  1137. {
  1138. if( m_dwReadFromSocketIoLength )
  1139. {
  1140. if( !ProcessUserDataReadFromSocket( m_dwReadFromSocketIoLength ) )
  1141. {
  1142. ioOpsToPerform2 |= IO_FAIL;
  1143. }
  1144. }
  1145. }
  1146. return ( ioOpsToPerform1 | ioOpsToPerform2 );
  1147. }
  1148. bool
  1149. CIoHandler::WriteToServer ( UCHAR ucMsg, DWORD dwMsgSize, LPVOID lpData )
  1150. {
  1151. if( lpData )
  1152. {
  1153. //The whole record should be available with the header.
  1154. //Otherwise, unnecessary allocations have to be done
  1155. if( !WriteToPipe( m_hWritePipe, lpData, dwMsgSize, &m_oWriteToPipe ) )
  1156. {
  1157. return( FALSE );
  1158. }
  1159. }
  1160. else
  1161. {
  1162. if( !WriteToPipe( m_hWritePipe, ucMsg, &m_oWriteToPipe ) )
  1163. {
  1164. return( FALSE );
  1165. }
  1166. }
  1167. return( TRUE );
  1168. }
  1169. bool
  1170. CIoHandler::IssueReadOnPipe()
  1171. {
  1172. _chASSERT( m_pucReadBuffer );
  1173. if( m_hReadPipe == INVALID_HANDLE_VALUE || !m_pucReadBuffer)
  1174. {
  1175. return ( FALSE );
  1176. }
  1177. if( !ReadFile( m_hReadPipe, m_pucReadBuffer, m_dwRequestedSize,
  1178. &m_dwReadFromPipeIoLength, &m_oReadFromPipe ) )
  1179. {
  1180. DWORD dwError = GetLastError( );
  1181. if ( ( dwError != ERROR_MORE_DATA ) && ( dwError != ERROR_IO_PENDING ) )
  1182. {
  1183. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READPIPE, dwError );
  1184. _TRACE( TRACE_DEBUGGING, " Error: ReadFile ( IssueReadOnPipe) -- 0x%1x ", dwError );
  1185. return ( FALSE );
  1186. }
  1187. }
  1188. return( TRUE );
  1189. }
  1190. bool
  1191. CIoHandler::IssueFirstReadOnPipe ( )
  1192. {
  1193. if( m_hReadPipe == INVALID_HANDLE_VALUE )
  1194. {
  1195. return ( FALSE );
  1196. }
  1197. if( !ReadFile( m_hReadPipe, &m_protocolInfo, sizeof( m_protocolInfo ),
  1198. &m_dwReadFromPipeIoLength, &m_oReadFromPipe ) )
  1199. {
  1200. DWORD dwError = GetLastError( );
  1201. if( dwError != ERROR_IO_PENDING )
  1202. {
  1203. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READPIPE, dwError );
  1204. _TRACE( TRACE_DEBUGGING, " Error: ReadFile ( IssueFirstReadOnPipe ) -- 0x%1x ", dwError );
  1205. return ( FALSE );
  1206. }
  1207. }
  1208. return( TRUE );
  1209. }
  1210. bool
  1211. CIoHandler::GetAndSetSocket ( )
  1212. {
  1213. int iAddressFamily = m_protocolInfo.iAddressFamily;
  1214. m_sSocket = WSASocket( iAddressFamily, SOCK_STREAM, 0, &m_protocolInfo,
  1215. NULL, NULL);
  1216. if( INVALID_SOCKET == m_sSocket )
  1217. {
  1218. DecodeWSAErrorCodes( WSAGetLastError() );//It logs and traces
  1219. return ( FALSE );
  1220. }
  1221. _chVERIFY2( SetHandleInformation( ( HANDLE ) m_sSocket,
  1222. 0, HANDLE_FLAG_INHERIT ) );
  1223. //mark the socket non-blocking
  1224. unsigned long ulNonBlocked = 1;
  1225. if( ioctlsocket( m_sSocket, FIONBIO, (u_long FAR*) &ulNonBlocked ) ==
  1226. SOCKET_ERROR )
  1227. {
  1228. _TRACE( TRACE_DEBUGGING, "Error: ioctlsocket() -- 0x%1x",
  1229. WSAGetLastError() );
  1230. return ( FALSE );
  1231. }
  1232. INT izero = 0;
  1233. DWORD dwStatus;
  1234. {
  1235. BOOL value_to_set = TRUE;
  1236. setsockopt(
  1237. m_sSocket,
  1238. SOL_SOCKET,
  1239. SO_DONTLINGER,
  1240. ( char * )&value_to_set,
  1241. sizeof( value_to_set )
  1242. );
  1243. }
  1244. dwStatus = SafeSetSocketOptions(m_sSocket);
  1245. if(dwStatus == SOCKET_ERROR)
  1246. {
  1247. _TRACE( TRACE_DEBUGGING, "Error: setsockopt() : %lu", GetLastError() );
  1248. return ( FALSE );
  1249. }
  1250. //Set send buffer size to zero
  1251. dwStatus = setsockopt( m_sSocket, SOL_SOCKET, SO_SNDBUF, ( char* ) &izero,
  1252. sizeof( izero ) );
  1253. if( dwStatus == SOCKET_ERROR )
  1254. {
  1255. _TRACE( TRACE_DEBUGGING, "Error: setsockopt() : %lu", GetLastError() );
  1256. return ( FALSE );
  1257. }
  1258. //This needs to be removed when we start handling urgent data as per RFC
  1259. //Make OOB inline
  1260. izero = TRUE;
  1261. dwStatus = setsockopt( m_sSocket, SOL_SOCKET, SO_OOBINLINE, ( char* ) &izero,
  1262. sizeof( izero ) );
  1263. if( dwStatus == SOCKET_ERROR )
  1264. {
  1265. _TRACE( TRACE_DEBUGGING, "Error: setsockopt() : %lu", GetLastError() );
  1266. return ( FALSE );
  1267. }
  1268. return( TRUE );
  1269. }
  1270. void
  1271. CIoHandler::DisplayOnClientNow()
  1272. {
  1273. if( m_pSession->CScraper::m_dwPollInterval != INFINITE )
  1274. {
  1275. //Scraper has been initialized;
  1276. m_pSession->CScraper::OnWaitTimeOut();
  1277. }
  1278. }
  1279. void
  1280. CIoHandler::SendMessageToClient( LPWSTR szMsg, bool bNeedHeader )
  1281. {
  1282. _chASSERT( szMsg );
  1283. if( !szMsg )
  1284. {
  1285. return;
  1286. }
  1287. LPTSTR szHeader = NULL;
  1288. if( bNeedHeader )
  1289. {
  1290. GetHeaderMessage( &szHeader );
  1291. }
  1292. if( m_pSession->CSession::m_bIsStreamMode || m_SocketControlState != STATE_SESSION )
  1293. {
  1294. DWORD dwNumBytesWritten = 0;
  1295. if( szHeader && bNeedHeader )
  1296. {
  1297. WriteMessageToClientDirectly( szHeader );
  1298. FinishIncompleteIo( ( HANDLE ) m_sSocket, &m_oWriteToSocket, &dwNumBytesWritten );
  1299. }
  1300. WriteMessageToClientDirectly( szMsg );
  1301. FinishIncompleteIo( ( HANDLE ) m_sSocket, &m_oWriteToSocket, &dwNumBytesWritten );
  1302. }
  1303. else
  1304. {
  1305. if( szHeader && bNeedHeader )
  1306. {
  1307. m_pSession->CScraper::WriteMessageToCmd( szHeader );
  1308. }
  1309. m_pSession->CScraper::WriteMessageToCmd( szMsg );
  1310. DisplayOnClientNow();
  1311. }
  1312. delete[] szHeader;
  1313. }
  1314. bool
  1315. CIoHandler::HandlePipeData ( )
  1316. {
  1317. bool bRetVal = TRUE;
  1318. m_dwRequestedSize = IPC_HEADER_SIZE; //How much data to read in the
  1319. // next call
  1320. switch( m_ReadFromPipeBuffer[0] )
  1321. {
  1322. case TLNTSVR_SHUTDOWN:
  1323. SendMessageToClient( SERVER_SHUTDOWN_MSG, NEED_HEADER );
  1324. return( FALSE ); //This should take us out of loop in
  1325. //WaitForIo
  1326. case GO_DOWN:
  1327. SendMessageToClient( GO_DOWN_MSG, NO_HEADER );
  1328. return( FALSE );
  1329. case SYSTEM_SHUTDOWN:
  1330. SendMessageToClient( SYSTEM_SHUTDOWN_MSG, NEED_HEADER );
  1331. return( FALSE );
  1332. case LICENSE_AVAILABLE:
  1333. m_iResult = ISSUE_LICENSE;
  1334. break;
  1335. case LICENSE_NOT_AVAILABLE:
  1336. m_iResult = DENY_LICENSE;
  1337. break;
  1338. case OPERATOR_MESSAGE:
  1339. if( !HandleOperatorMessage() )
  1340. {
  1341. bRetVal = FALSE;
  1342. }
  1343. break;
  1344. default:
  1345. break;
  1346. }
  1347. return ( bRetVal );
  1348. }
  1349. /* Generally we read data on pipe into a IPC_HEADER_SIZE buffer of m_ReadFromPipeBuffer.
  1350. When, it is an operator message we issue async read into a specially allocated block and free on
  1351. actual reception */
  1352. bool
  1353. CIoHandler::HandleOperatorMessage()
  1354. {
  1355. bool bRetVal = TRUE;
  1356. if ( m_bIpcHeader )
  1357. {
  1358. m_bIpcHeader = false;
  1359. memcpy( &m_dwRequestedSize, m_ReadFromPipeBuffer + sizeof( UCHAR ), sizeof( DWORD ) );
  1360. m_pucReadBuffer = new UCHAR[ m_dwRequestedSize + wcslen( FOOTER ) + 2 ];
  1361. if( !m_pucReadBuffer )
  1362. {
  1363. bRetVal = FALSE;
  1364. }
  1365. }
  1366. else
  1367. {
  1368. wcscat( ( LPWSTR )m_pucReadBuffer, FOOTER );
  1369. SendMessageToClient( ( LPWSTR )m_pucReadBuffer, NEED_HEADER );
  1370. delete[] m_pucReadBuffer;
  1371. m_pucReadBuffer = m_ReadFromPipeBuffer;
  1372. m_bIpcHeader = true;
  1373. }
  1374. return( bRetVal );
  1375. }
  1376. bool
  1377. CIoHandler::OnReadFromPipeCompletion ( )
  1378. {
  1379. bool bRetVal = FALSE;
  1380. if( m_fFirstReadFromPipe )
  1381. {
  1382. m_fFirstReadFromPipe = false;
  1383. if( GetAndSetSocket() )
  1384. {
  1385. m_pSession->CollectPeerInfo();
  1386. m_pSession->CRFCProtocol::InitialNegotiation();
  1387. //The negotiation leaves the data in the buffer
  1388. if( WriteToClient( ) )
  1389. {
  1390. bRetVal = TRUE;
  1391. m_pSession->AddHandleToWaitOn( m_oReadFromSocket.hEvent );
  1392. IssueReadFromSocket();
  1393. }
  1394. }
  1395. }
  1396. else
  1397. {
  1398. bRetVal = HandlePipeData();
  1399. }
  1400. if( bRetVal == TRUE )
  1401. {
  1402. bRetVal = IssueReadOnPipe( );
  1403. }
  1404. return ( bRetVal );
  1405. }
  1406. bool
  1407. CIoHandler::WriteToClient ( )
  1408. {
  1409. DWORD dwBytesWritten;
  1410. if( m_dwWriteToSocketIoLength > 0 && (!WriteFile( ( HANDLE ) m_sSocket, m_WriteToSocketBuff,
  1411. m_dwWriteToSocketIoLength, &dwBytesWritten, &m_oWriteToSocket )))
  1412. {
  1413. DWORD dwErr;
  1414. if( ( dwErr = GetLastError( ) ) != ERROR_IO_PENDING )
  1415. {
  1416. if( dwErr != ERROR_NETNAME_DELETED )
  1417. {
  1418. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_WRITESOCKET, dwErr );
  1419. _TRACE( TRACE_DEBUGGING, "Error: WriteFile(WriteToClient) -- 0x%1x", dwErr );
  1420. }
  1421. return( FALSE );
  1422. }
  1423. }
  1424. m_dwWriteToSocketIoLength = 0;
  1425. if( m_fShutDownAfterIO )
  1426. {
  1427. return( FALSE ); //This Should lead to exit from WaitForIo loop
  1428. }
  1429. return ( TRUE );
  1430. }
  1431. bool
  1432. CIoHandler::IssueReadFromSocket ( )
  1433. {
  1434. DWORD dwRequestedIoSize = AVAILABE_BUFFER_SIZE( m_ReadFromSocketBuffer,
  1435. m_pReadFromSocketBufferCursor );
  1436. if( !ReadFile( ( HANDLE ) m_sSocket, m_pReadFromSocketBufferCursor,
  1437. dwRequestedIoSize, &m_dwReadFromSocketIoLength, &m_oReadFromSocket ) )
  1438. {
  1439. DWORD dwError = GetLastError( );
  1440. //ERROR_NETNAME_DELETED results when the client aborts the connection
  1441. if( ( dwError != ERROR_MORE_DATA ) && ( dwError != ERROR_IO_PENDING ) )
  1442. {
  1443. if( dwError != ERROR_NETNAME_DELETED)
  1444. {
  1445. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_READSOCKET, dwError );
  1446. _TRACE( TRACE_DEBUGGING, " Error: ReadFile(IssueReadFromSocket) -- 0x%1x ", dwError );
  1447. }
  1448. return ( FALSE );
  1449. }
  1450. }
  1451. return( TRUE );
  1452. }
  1453. bool
  1454. CIoHandler::OnReadFromSocketCompletion ( )
  1455. {
  1456. IO_OPERATIONS ioOpsToPerform = 0;
  1457. BOOL dwStatus = 0;
  1458. _chVERIFY2( dwStatus = GetOverlappedResult( ( HANDLE )m_sSocket,
  1459. &m_oReadFromSocket, &m_dwReadFromSocketIoLength, FALSE ) );
  1460. if( !dwStatus )
  1461. {
  1462. return( FALSE );
  1463. }
  1464. if( m_dwReadFromSocketIoLength == 0 )
  1465. {
  1466. return( FALSE );
  1467. }
  1468. ioOpsToPerform = OnDataFromSocket( );
  1469. if( ( ioOpsToPerform & WRITE_TO_SOCKET ) )
  1470. {
  1471. if( !WriteToClient( ) )
  1472. {
  1473. return( FALSE );
  1474. }
  1475. }
  1476. if( ioOpsToPerform & IO_FAIL )
  1477. {
  1478. _chASSERT( 0 );
  1479. WriteMessageToClientDirectly( TEXT( BUGGY_SESSION_DATA ) );
  1480. WriteToClient( );
  1481. return( FALSE );
  1482. }
  1483. return ( IssueReadFromSocket() );
  1484. }
  1485. /*There are 2 ways to send data to client.
  1486. 1. Write to cmd. Let scraper send it.
  1487. 2. Write to socket directly. The following is the implementation.
  1488. */
  1489. void
  1490. CIoHandler::WriteMessageToClientDirectly( LPWSTR szMsg )
  1491. {
  1492. LPSTR szBuf = NULL;
  1493. DWORD dwSize = 0;
  1494. DWORD dwNumBytesWritten = 0;
  1495. int iRet = 0;
  1496. _chASSERT( szMsg );
  1497. if( !szMsg )
  1498. {
  1499. goto End;
  1500. }
  1501. _chVERIFY2( dwSize = WideCharToMultiByte( GetConsoleCP(), 0, szMsg, -1, NULL, 0, NULL, NULL ) );
  1502. szBuf = new CHAR[ dwSize ];
  1503. if( szBuf )
  1504. {
  1505. iRet = WideCharToMultiByte( GetConsoleCP(), 0, szMsg, -1, szBuf, dwSize, NULL, NULL );
  1506. _chVERIFY2(iRet);
  1507. if(!iRet)
  1508. {
  1509. goto End;
  1510. }
  1511. if( !FinishIncompleteIo( ( HANDLE ) m_sSocket, &( m_oWriteToSocket ), &dwNumBytesWritten ) )
  1512. {
  1513. goto End;
  1514. }
  1515. StuffEscapeIACs( m_WriteToSocketBuff, ( PUCHAR )szBuf, &dwSize );
  1516. m_dwWriteToSocketIoLength = dwSize;
  1517. WriteToClient( );
  1518. }
  1519. End:
  1520. if(szBuf)
  1521. {
  1522. delete[] szBuf;
  1523. }
  1524. return;
  1525. }
  1526. void
  1527. CIoHandler::UpdateIdleTime( UCHAR ucChangeIdleTime )
  1528. {
  1529. WriteToServer( ucChangeIdleTime, 0, NULL );
  1530. }
  1531. //caller has to free *szHeader
  1532. bool CIoHandler::GetHeaderMessage( LPWSTR *szHeader )
  1533. {
  1534. bool bRetVal = false;
  1535. UDATE uSysDate; //local time
  1536. DATE dtCurrent;
  1537. DWORD dwSize = 0;
  1538. BSTR szDate = NULL;
  1539. WCHAR szMachineName[ MAX_COMPUTERNAME_LENGTH + 1];
  1540. _chASSERT( g_szHeaderFormat );
  1541. if( !szHeader )
  1542. {
  1543. _chASSERT( szHeader );
  1544. goto ExitOnError;
  1545. }
  1546. *szHeader = NULL;
  1547. GetLocalTime( &uSysDate.st );
  1548. if( VarDateFromUdate( &uSysDate, VAR_VALIDDATE, &dtCurrent ) != S_OK )
  1549. {
  1550. goto ExitOnError;
  1551. }
  1552. if( VarBstrFromDate( dtCurrent,
  1553. MAKELCID( MAKELANGID( LANG_NEUTRAL, SUBLANG_SYS_DEFAULT ), SORT_DEFAULT ),
  1554. LOCALE_NOUSEROVERRIDE, &szDate ) != S_OK )
  1555. {
  1556. goto ExitOnError;
  1557. }
  1558. *szHeader = new WCHAR[ wcslen( g_szHeaderFormat ) + wcslen( szDate ) +
  1559. MAX_COMPUTERNAME_LENGTH + 1 ];
  1560. if( !*szHeader )
  1561. {
  1562. goto ExitOnError;
  1563. }
  1564. //Get Computer name
  1565. dwSize = sizeof( szMachineName )/sizeof(WCHAR);
  1566. szMachineName[0] = L'\0';
  1567. if( !GetComputerName( szMachineName, &dwSize ) )
  1568. {
  1569. szMachineName[0] = L'\0';
  1570. }
  1571. //Form the message
  1572. wsprintf( *szHeader, g_szHeaderFormat, szMachineName, szDate );
  1573. bRetVal = true;
  1574. ExitOnError:
  1575. SysFreeString( szDate );
  1576. return bRetVal;
  1577. }