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.

2444 lines
81 KiB

  1. // TelnSrv.cpp : This file contains the
  2. // Created: Jan '98
  3. // Author : a-rakeba
  4. // History:
  5. // Copyright (C) 1998 Microsoft Corporation
  6. // All rights reserved.
  7. // Microsoft Confidential
  8. #include <StdAfx.h>
  9. #include <TChar.h>
  10. #include <Debug.h>
  11. #include <MsgFile.h>
  12. #include <RegUtil.h>
  13. #include <TelnetD.h>
  14. #include <TlntUtils.h>
  15. #include <TlntDynamicArray.h>
  16. #include <TelntSrv.h>
  17. #include <Ipc.h>
  18. #include <Resource.h>
  19. #include <wincrypt.h>
  20. #pragma warning( disable: 4706 )
  21. using namespace _Utils;
  22. using CDebugLevel::TRACE_DEBUGGING;
  23. using CDebugLevel::TRACE_HANDLE;
  24. using CDebugLevel::TRACE_SOCKET;
  25. extern TCHAR g_szMaxConnectionsReached[ MAX_STRING_LENGTH ];
  26. extern HINSTANCE g_hInstRes;
  27. extern LPWSTR g_pszTelnetInstallPath;
  28. extern HANDLE *g_phLogFile;
  29. extern LPWSTR g_pszLogFile;
  30. extern LONG g_lMaxFileSize;
  31. extern bool g_fLogToFile;
  32. extern HANDLE g_hSyncCloseHandle;
  33. extern CTelnetService* g_pTelnetService;
  34. extern HCRYPTPROV g_hProv;
  35. #define WINSTA_ALL (WINSTA_ACCESSCLIPBOARD | WINSTA_ACCESSGLOBALATOMS | \
  36. WINSTA_CREATEDESKTOP | WINSTA_ENUMDESKTOPS | \
  37. WINSTA_ENUMERATE | WINSTA_EXITWINDOWS | \
  38. WINSTA_READATTRIBUTES | WINSTA_READSCREEN | \
  39. WINSTA_WRITEATTRIBUTES | DELETE | \
  40. READ_CONTROL | WRITE_DAC | \
  41. WRITE_OWNER)
  42. bool SetWinstaSecurity()
  43. {
  44. bool bStatus = FALSE;
  45. BOOL bRetVal = FALSE;
  46. DWORD dwErrCode = 0;
  47. PSID pSidAdministrators = NULL, pSidLocalSystem = NULL, pSidLocalService = NULL, pSidNetworkService = NULL, pSidTelnetClients = NULL;
  48. PACL newACL = NULL;
  49. SECURITY_DESCRIPTOR sd = { 0 };
  50. HWINSTA window_station = NULL;
  51. SECURITY_ATTRIBUTES sa = { 0 };
  52. SECURITY_INFORMATION sec_i = DACL_SECURITY_INFORMATION;
  53. DWORD aclSize;
  54. SID_IDENTIFIER_AUTHORITY local_system_authority = SECURITY_NT_AUTHORITY;
  55. SID_IDENTIFIER_AUTHORITY worldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  56. ACCESS_ALLOWED_ACE *pace = NULL;
  57. //Build administrators alias sid
  58. if (! AllocateAndInitializeSid(
  59. &local_system_authority,
  60. 2, /* there are only two sub-authorities */
  61. SECURITY_BUILTIN_DOMAIN_RID,
  62. DOMAIN_ALIAS_RID_ADMINS,
  63. 0,0,0,0,0,0, /* Don't care about the rest */
  64. &pSidAdministrators
  65. ))
  66. {
  67. goto ExitOnError;
  68. }
  69. //Build LocalSystem sid
  70. if (! AllocateAndInitializeSid(
  71. &local_system_authority,
  72. 1, /* there is only one sub-authority */
  73. SECURITY_LOCAL_SYSTEM_RID,
  74. 0,0,0,0,0,0,0, /* Don't care about the rest */
  75. &pSidLocalSystem
  76. ))
  77. {
  78. goto ExitOnError;
  79. }
  80. #ifndef SECURITY_LOCAL_SERVICE_RID
  81. #define SECURITY_LOCAL_SERVICE_RID (0x00000013L)
  82. #define SECURITY_NETWORK_SERVICE_RID (0x00000014L)
  83. #endif
  84. //Build LocalLocal sid
  85. if ( ! AllocateAndInitializeSid(
  86. &local_system_authority,
  87. 1, /* there is only one sub-authority */
  88. SECURITY_LOCAL_SERVICE_RID,
  89. 0,0,0,0,0,0,0, /* Don't care about the rest */
  90. &pSidLocalService
  91. ) )
  92. {
  93. goto ExitOnError;
  94. }
  95. /*
  96. //Build LocalSystem sid
  97. if ( ! AllocateAndInitializeSid(
  98. &local_system_authority,
  99. 1, /* there is only one sub-authority /
  100. SECURITY_NETWORK_SERVICE_RID,
  101. 0,0,0,0,0,0,0, /* Don't care about the rest /
  102. &pSidNetworkService
  103. ) )
  104. {
  105. goto ExitOnError;
  106. }
  107. */
  108. {
  109. DWORD needed_length = 0;
  110. DWORD dwErr = 0, dwDomainLen = 0;
  111. SID_NAME_USE sidNameUse;
  112. TCHAR szDomain[ MAX_PATH + 1 ];
  113. BOOL success = FALSE;
  114. TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1 + 14] = { 0 }; //+14 for '\TelnetClients'
  115. DWORD dwNameLen = MAX_COMPUTERNAME_LENGTH + 1;
  116. success = GetComputerName(szComputerName, &dwNameLen);
  117. if(success)
  118. {
  119. _sntprintf(szComputerName+dwNameLen,(MAX_COMPUTERNAME_LENGTH + 14) - dwNameLen,_T("\\%s"),TELNETCLIENTS_GROUP_NAME);
  120. }
  121. LookupAccountName( NULL, szComputerName, pSidTelnetClients, &needed_length,
  122. szDomain, &dwDomainLen, &sidNameUse );
  123. pSidTelnetClients = ( PSID ) new UCHAR[ needed_length ];
  124. //Even if if allocation fails just go ahead.
  125. success = LookupAccountName( NULL, szComputerName, pSidTelnetClients, &needed_length,
  126. szDomain, &dwDomainLen, &sidNameUse );
  127. if( !success )
  128. {
  129. if (pSidTelnetClients)
  130. {
  131. delete pSidTelnetClients;
  132. pSidTelnetClients = NULL;
  133. }
  134. }
  135. }
  136. if(pSidTelnetClients == NULL)
  137. { //Allocate size for 4 ACEs.
  138. aclSize = sizeof(ACL) +
  139. (3* sizeof(ACCESS_ALLOWED_ACE)) +
  140. GetLengthSid(pSidAdministrators) +
  141. GetLengthSid(pSidLocalSystem) +
  142. GetLengthSid(pSidLocalService) +
  143. //GetLengthSid(pSidNetworkService) -
  144. (3*sizeof(DWORD));
  145. }
  146. else
  147. { //Allocate size for 5 ACEs. TelnetClients group is present and we should provide access to
  148. //members of telnetclients group
  149. aclSize = sizeof(ACL) +
  150. (4* sizeof(ACCESS_ALLOWED_ACE)) +
  151. GetLengthSid(pSidAdministrators) +
  152. GetLengthSid(pSidLocalSystem) +
  153. GetLengthSid(pSidLocalService) +
  154. //GetLengthSid(pSidNetworkService) +
  155. GetLengthSid(pSidTelnetClients) -
  156. (4*sizeof(DWORD));
  157. }
  158. newACL = (PACL) new BYTE[aclSize];
  159. if (newACL == NULL)
  160. {
  161. goto ExitOnError;
  162. }
  163. if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
  164. {
  165. goto ExitOnError;
  166. }
  167. if(pSidTelnetClients != NULL)
  168. {
  169. pace = (ACCESS_ALLOWED_ACE *)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSidTelnetClients) -sizeof(DWORD));
  170. if (pace == NULL)
  171. {
  172. goto ExitOnError;
  173. }
  174. pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  175. pace->Header.AceFlags = CONTAINER_INHERIT_ACE |
  176. OBJECT_INHERIT_ACE;
  177. pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) +
  178. (WORD)GetLengthSid(pSidTelnetClients) - sizeof(DWORD);
  179. pace->Mask = WINSTA_ALL &
  180. ~(WRITE_DAC |
  181. WRITE_OWNER |
  182. WINSTA_CREATEDESKTOP |
  183. DELETE);
  184. if (!CopySid(GetLengthSid(pSidTelnetClients), &pace->SidStart, pSidTelnetClients))
  185. {
  186. goto ExitOnError;
  187. }
  188. if (!AddAce(newACL,ACL_REVISION,MAXDWORD,(LPVOID)pace,pace->Header.AceSize))
  189. {
  190. goto ExitOnError;
  191. }
  192. }
  193. if (!AddAccessAllowedAce(newACL, ACL_REVISION, GENERIC_ALL , pSidAdministrators))
  194. {
  195. goto ExitOnError;
  196. }
  197. if (!AddAccessAllowedAce(newACL, ACL_REVISION, GENERIC_ALL, pSidLocalSystem))
  198. {
  199. goto ExitOnError;
  200. }
  201. if (!AddAccessAllowedAce(newACL, ACL_REVISION, GENERIC_ALL , pSidLocalService))
  202. {
  203. goto ExitOnError;
  204. }
  205. /*
  206. if (!AddAccessAllowedAce(newACL, ACL_REVISION, GENERIC_ALL , pSidNetworkService))
  207. {
  208. goto ExitOnError;
  209. }
  210. */
  211. if ( !InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION ) )
  212. {
  213. goto ExitOnError;
  214. }
  215. if ( !SetSecurityDescriptorDacl(&sd, TRUE, newACL, FALSE) )
  216. {
  217. goto ExitOnError;
  218. }
  219. window_station = GetProcessWindowStation(); // Will this always have WRITE_DAC, we're the owner
  220. if (NULL == window_station)
  221. {
  222. goto ExitOnError;
  223. }
  224. if (! SetUserObjectSecurity(window_station, &sec_i, &sd))
  225. {
  226. goto ExitOnError;
  227. }
  228. bStatus = TRUE;
  229. goto Done;
  230. ExitOnError:
  231. dwErrCode = GetLastError();
  232. _TRACE(TRACE_DEBUGGING,L"Creation and setting of windowstation/desktop failed with %d",dwErrCode);
  233. LogFormattedGetLastError(EVENTLOG_ERROR_TYPE, TELNET_MSG_ERROR_CREATE_DESKTOP_FAILURE, dwErrCode);
  234. Done:
  235. if (window_station)
  236. {
  237. CloseWindowStation(window_station);
  238. }
  239. if ( pSidAdministrators != NULL )
  240. {
  241. FreeSid (pSidAdministrators );
  242. }
  243. if ( pSidLocalSystem!= NULL )
  244. {
  245. FreeSid (pSidLocalSystem);
  246. }
  247. if ( pSidLocalService!= NULL )
  248. {
  249. FreeSid (pSidLocalService);
  250. }
  251. if ( pSidNetworkService!= NULL )
  252. {
  253. FreeSid (pSidNetworkService);
  254. }
  255. if(pace)
  256. HeapFree(GetProcessHeap(), 0, (LPVOID)pace);
  257. if (pSidTelnetClients)
  258. {
  259. delete pSidTelnetClients;
  260. pSidTelnetClients = NULL;
  261. }
  262. if (newACL)
  263. delete [] newACL;
  264. return( bStatus );
  265. }
  266. CTelnetService* CTelnetService::s_instance = NULL;
  267. CTelnetService*
  268. CTelnetService::Instance()
  269. {
  270. if ( s_instance == NULL )
  271. {
  272. s_instance = new CTelnetService();
  273. _chASSERT( s_instance != NULL );
  274. }
  275. return( s_instance );
  276. }
  277. void
  278. CTelnetService::InitializeOverlappedStruct( LPOVERLAPPED poObject )
  279. {
  280. _chASSERT( poObject != NULL );
  281. if ( !poObject )
  282. {
  283. return;
  284. }
  285. poObject->Internal = 0;
  286. poObject->InternalHigh = 0;
  287. poObject->Offset = 0;
  288. poObject->OffsetHigh = 0;
  289. poObject->hEvent = NULL;
  290. return;
  291. }
  292. CTelnetService::CTelnetService()
  293. {
  294. m_dwTelnetPort = DEFAULT_TELNET_PORT;
  295. m_dwMaxConnections = 0;
  296. m_pszIpAddrToListenOn = NULL;
  297. m_hReadConfigKey = NULL;
  298. m_dwNumOfActiveConnections = 0;
  299. m_lServerState = SERVER_RUNNING;
  300. SfuZeroMemory(m_sFamily, sizeof(m_sFamily));
  301. m_sFamily[IPV4_FAMILY].iFamily = AF_INET;
  302. m_sFamily[IPV4_FAMILY].iSocklen = sizeof(SOCKADDR_IN);
  303. m_sFamily[IPV4_FAMILY].sListenSocket = INVALID_SOCKET;
  304. m_sFamily[IPV6_FAMILY].iFamily = AF_INET6;
  305. m_sFamily[IPV6_FAMILY].iSocklen = sizeof(SOCKADDR_IN6);
  306. m_sFamily[IPV6_FAMILY].sListenSocket = INVALID_SOCKET;
  307. m_hCompletionPort = INVALID_HANDLE_VALUE;
  308. m_hIPCThread = NULL;
  309. InitializeOverlappedStruct( &m_oReadFromPipe );
  310. InitializeOverlappedStruct( &m_oWriteToPipe );
  311. InitializeOverlappedStruct( &m_oPostedMessage );
  312. client_list_mutex = TnCreateMutex(NULL, FALSE, NULL);
  313. CQList = new CQueue;
  314. _chASSERT( client_list_mutex );
  315. _chVERIFY2( m_hSyncAllClientObjAccess = TnCreateMutex( NULL, FALSE, NULL ) );
  316. // DebugBreak();
  317. _chVERIFY2( m_hSocketCloseEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) );
  318. _chVERIFY2( m_hRegChangeEvent = CreateEvent( NULL, TRUE, FALSE, NULL ) );
  319. _chVERIFY2( g_hSyncCloseHandle = TnCreateMutex(NULL,FALSE,NULL));
  320. m_bIsWorkStation = false;;
  321. m_pssWorkstationList = NULL;
  322. m_dwNoOfWorkstations = 0;
  323. }
  324. CTelnetService::~CTelnetService()
  325. {
  326. delete[] m_pszIpAddrToListenOn;
  327. delete[] m_pssWorkstationList;
  328. TELNET_CLOSE_HANDLE(g_hSyncCloseHandle);
  329. TELNET_CLOSE_HANDLE(client_list_mutex);
  330. //All the cleanup is happening in Shutdown()
  331. }
  332. bool
  333. CTelnetService::WatchRegistryKeys()
  334. {
  335. DWORD dwStatus = 0;
  336. DWORD dwDisp = 0;
  337. if ( dwStatus = TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, READ_CONFIG_KEY, NULL, NULL,
  338. REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL,
  339. &m_hReadConfigKey, &dwDisp, 0 ) )
  340. {
  341. return( FALSE );
  342. }
  343. if ( !RegisterForNotification() )
  344. {
  345. return( FALSE );
  346. }
  347. return( TRUE );
  348. }
  349. bool
  350. CTelnetService::RegisterForNotification()
  351. {
  352. DWORD dwStatus = 0;
  353. if ( dwStatus = RegNotifyChangeKeyValue( m_hReadConfigKey, TRUE,
  354. REG_NOTIFY_CHANGE_LAST_SET|REG_NOTIFY_CHANGE_NAME,
  355. m_hRegChangeEvent, TRUE ) != ERROR_SUCCESS )
  356. {
  357. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_REGNOTIFY, dwStatus );
  358. return( FALSE );
  359. }
  360. return( TRUE );
  361. }
  362. bool
  363. CTelnetService::Init( void )
  364. {
  365. if ( !m_hSyncAllClientObjAccess || !m_hSocketCloseEvent || !m_hRegChangeEvent )
  366. {
  367. return( FALSE);
  368. }
  369. if ( !GetRegistryValues() )
  370. {
  371. return( FALSE );
  372. }
  373. if ( !WatchRegistryKeys() )
  374. {
  375. return( FALSE );
  376. }
  377. if ( !InitTCPIP() )
  378. {
  379. return( FALSE );
  380. }
  381. if( !SetWinstaSecurity())
  382. {
  383. return ( FALSE );
  384. }
  385. m_szDomainName[0] = L'\0';
  386. if ( !GetDomainHostedByThisMc( m_szDomainName ) )
  387. {
  388. m_szDomainName[0] = 0;
  389. }
  390. LPWSTR szProductType = NULL;
  391. if ( !GetProductType( &szProductType ) )
  392. {
  393. return( FALSE);
  394. }
  395. m_bIsWorkStation = ( _wcsicmp(szProductType, TEXT("WinNT")) == 0 );
  396. delete[] szProductType;
  397. if ( m_bIsWorkStation )
  398. {
  399. m_pssWorkstationList = new SOCKADDR_STORAGE[ DEFAULT_LICENSES_FOR_NTWKSTA ];
  400. if ( !m_pssWorkstationList )
  401. {
  402. return( FALSE);
  403. }
  404. }
  405. return( TRUE );
  406. }
  407. bool
  408. CTelnetService::Pause( void )
  409. {
  410. InterlockedExchange( &m_lServerState, SERVER_PAUSED );
  411. return( TRUE );
  412. }
  413. bool
  414. CTelnetService::Resume( void )
  415. {
  416. InterlockedExchange( &m_lServerState, SERVER_RUNNING );
  417. return( TRUE );
  418. }
  419. void
  420. CTelnetService::SystemShutdown( void )
  421. {
  422. //We have just 20 secs left to finish this routine
  423. if(m_hCompletionPort && m_hCompletionPort != INVALID_HANDLE_VALUE)
  424. PostQueuedCompletionStatus( m_hCompletionPort, 0, TLNTSVR_SHUTDOWN,
  425. &m_oPostedMessage ); //This should lead to IPC thread exit if
  426. //it is present.
  427. if (TlntSynchronizeOn(m_hSyncAllClientObjAccess))
  428. {
  429. DWORD dwCount = client_list_Count();
  430. while ( dwCount-- > 0 )
  431. {
  432. CClientInfo *pClient = (CClientInfo *)client_list_Get( dwCount );
  433. if ( pClient )
  434. {
  435. WriteToPipe( pClient->hWritingPipe, SYSTEM_SHUTDOWN,
  436. &( m_oWriteToPipe ) );
  437. }
  438. }
  439. ReleaseMutex( m_hSyncAllClientObjAccess );
  440. }
  441. return;
  442. }
  443. bool
  444. CTelnetService::AskSessionToShutdown( HANDLE hWritingPipe, UCHAR ucMsgType )
  445. {
  446. if ( !WriteToPipe( hWritingPipe, ucMsgType, &( m_oWriteToPipe ) ) )
  447. {
  448. return( FALSE );
  449. }
  450. return( TRUE );
  451. }
  452. bool
  453. CTelnetService::Shutdown( void )
  454. {
  455. shutdown( m_sFamily[IPV4_FAMILY].sListenSocket, SD_BOTH ); //NO more data on socket
  456. shutdown( m_sFamily[IPV6_FAMILY].sListenSocket, SD_BOTH ); //NO more data on socket
  457. if(m_hCompletionPort && m_hCompletionPort != INVALID_HANDLE_VALUE)
  458. PostQueuedCompletionStatus( m_hCompletionPort, 0, TLNTSVR_SHUTDOWN,
  459. &m_oPostedMessage );
  460. if (TlntSynchronizeOn(m_hSyncAllClientObjAccess))
  461. {
  462. _Module.SetServiceStatus( SERVICE_STOP_PENDING );
  463. while ( client_list_Count() > 0 )
  464. {
  465. CClientInfo *pClient = (CClientInfo *)client_list_Get( 0 );
  466. if ( !pClient )
  467. {
  468. break;
  469. }
  470. AskSessionToShutdown( pClient->hWritingPipe, TLNTSVR_SHUTDOWN );
  471. StopServicingClient( pClient, (BOOL)TRUE );
  472. }
  473. ReleaseMutex( m_hSyncAllClientObjAccess );
  474. }
  475. _Module.SetServiceStatus( SERVICE_STOP_PENDING );
  476. TELNET_SYNC_CLOSE_HANDLE( m_hSyncAllClientObjAccess );
  477. if ((NULL != m_hIPCThread) && (INVALID_HANDLE_VALUE != m_hIPCThread))
  478. {
  479. // WaitForSingleObject(m_hIPCThread, INFINITE);
  480. TerminateThread(m_hIPCThread, 0);
  481. TELNET_CLOSE_HANDLE( m_hIPCThread );
  482. }
  483. SetEvent( m_hSocketCloseEvent );//This should lead to listener thread exit
  484. return( TRUE );
  485. }
  486. bool
  487. CTelnetService::GetInAddr( INT iFamIdx, SOCKADDR_STORAGE *ssS_addr, socklen_t *iSslen )
  488. {
  489. bool bContinue = false;
  490. if ( wcscmp( m_pszIpAddrToListenOn, DEFAULT_IP_ADDR ) == 0 )
  491. {
  492. // Bind to "any"
  493. _TRACE(TRACE_DEBUGGING,"Into GetInAddr, bind to ANY");
  494. *iSslen = m_sFamily[iFamIdx].iSocklen;
  495. SfuZeroMemory(ssS_addr, *iSslen);
  496. ssS_addr->ss_family = (short)m_sFamily[iFamIdx].iFamily;
  497. bContinue = true;
  498. }
  499. else
  500. {
  501. DWORD dwSize = 0, dwResult;
  502. PCHAR szIpAddr = NULL;
  503. struct addrinfo *ai, hints;
  504. dwSize = WideCharToMultiByte( GetOEMCP(), 0, m_pszIpAddrToListenOn, -1, NULL, 0, NULL, NULL );
  505. _TRACE(TRACE_DEBUGGING,L"m_pszIpAddr : %s",m_pszIpAddrToListenOn);
  506. szIpAddr = new CHAR[ dwSize ];
  507. if ( !szIpAddr )
  508. {
  509. return FALSE;
  510. }
  511. WideCharToMultiByte( GetOEMCP(), 0, m_pszIpAddrToListenOn, -1, szIpAddr, dwSize, NULL, NULL );
  512. _TRACE(TRACE_DEBUGGING,"szIpAddr : %s",szIpAddr);
  513. SfuZeroMemory(&hints, sizeof(hints));
  514. hints.ai_flags = AI_NUMERICHOST;
  515. dwResult = getaddrinfo(szIpAddr, NULL, &hints, &ai);
  516. if ( dwResult != NO_ERROR )
  517. {
  518. //Log error
  519. LogEvent( EVENTLOG_ERROR_TYPE, MSG_FAILEDTO_BIND, m_pszIpAddrToListenOn );
  520. _TRACE(TRACE_DEBUGGING,"getaddrinfo failed : %d ",dwResult);
  521. delete[] szIpAddr;
  522. return FALSE;
  523. }
  524. else
  525. {
  526. switch ( ai->ai_family)
  527. {
  528. case AF_INET:
  529. if (iFamIdx == IPV4_FAMILY)
  530. {
  531. _TRACE(TRACE_DEBUGGING,"IPV4 family and IPV4 address");
  532. bContinue = true;
  533. }
  534. else
  535. {
  536. _TRACE(TRACE_DEBUGGING,"IPV4 family and IPV6 address...continue");
  537. SetLastError(ERROR_SUCCESS);
  538. }
  539. break;
  540. case AF_INET6:
  541. if (iFamIdx == IPV6_FAMILY)
  542. {
  543. _TRACE(TRACE_DEBUGGING,"IPV6 family and IPV6 address");
  544. bContinue = true;
  545. }
  546. else
  547. {
  548. _TRACE(TRACE_DEBUGGING,"IPV6 family and IPV4 address...continue");
  549. SetLastError(ERROR_SUCCESS);
  550. }
  551. break;
  552. default:
  553. _TRACE(TRACE_DEBUGGING,"none of the two ??");
  554. break;
  555. }
  556. if (bContinue)
  557. {
  558. *iSslen = ai->ai_addrlen;
  559. CopyMemory(ssS_addr, ai->ai_addr, ai->ai_addrlen);
  560. }
  561. }
  562. delete[] szIpAddr;
  563. }
  564. return( bContinue ? TRUE : FALSE );
  565. }
  566. bool
  567. CTelnetService::CreateSocket( INT iFamIdx )
  568. {
  569. INT iSize = 1, iSslen;
  570. DWORD dwCode = 0;
  571. struct sockaddr_storage ss;
  572. _chVERIFY2( SetHandleInformation( ( HANDLE ) m_sFamily[iFamIdx].SocketAcceptEvent,
  573. HANDLE_FLAG_INHERIT, 0 ) );
  574. _TRACE(TRACE_DEBUGGING,"Into CreateSocket");
  575. if ( !GetInAddr(iFamIdx, &ss, &iSslen ) )
  576. {
  577. _TRACE(TRACE_DEBUGGING,"GetInAddr failed");
  578. goto ExitOnError;
  579. }
  580. SS_PORT(&ss) = htons( ( u_short ) m_dwTelnetPort );
  581. m_sFamily[iFamIdx].sListenSocket = socket( m_sFamily[iFamIdx].iFamily, SOCK_STREAM, 0 );
  582. if ( INVALID_SOCKET == m_sFamily[iFamIdx].sListenSocket )
  583. {
  584. _TRACE(TRACE_DEBUGGING,"socket failed");
  585. goto ExitOnError;
  586. }
  587. {
  588. BOOL value_to_set = TRUE;
  589. if (SOCKET_ERROR == setsockopt(
  590. m_sFamily[iFamIdx].sListenSocket,
  591. SOL_SOCKET,
  592. SO_DONTLINGER,
  593. ( char * )&value_to_set,
  594. sizeof( value_to_set )
  595. )
  596. )
  597. {
  598. goto CloseAndExitOnError;
  599. }
  600. if(SOCKET_ERROR == SafeSetSocketOptions(m_sFamily[iFamIdx].sListenSocket))
  601. {
  602. goto CloseAndExitOnError;
  603. }
  604. }
  605. _TRACE(TRACE_DEBUGGING,"Scope id is : %ul",((sockaddr_in6 *)&ss)->sin6_scope_id);
  606. if ( bind( m_sFamily[iFamIdx].sListenSocket, ( struct sockaddr * ) &ss, iSslen ) == SOCKET_ERROR )
  607. {
  608. _TRACE(TRACE_DEBUGGING,"bind failed");
  609. goto CloseAndExitOnError;
  610. }
  611. if ( listen( m_sFamily[iFamIdx].sListenSocket, SOMAXCONN ) == SOCKET_ERROR )
  612. {
  613. _TRACE(TRACE_DEBUGGING,"listen failed");
  614. goto CloseAndExitOnError;
  615. }
  616. //We are making it non-inheritable here
  617. _chVERIFY2( SetHandleInformation( ( HANDLE ) m_sFamily[iFamIdx].sListenSocket,
  618. HANDLE_FLAG_INHERIT, 0 ) );
  619. if ( ( WSAEventSelect( m_sFamily[iFamIdx].sListenSocket, m_sFamily[iFamIdx].SocketAcceptEvent, FD_ACCEPT )
  620. == SOCKET_ERROR ) )
  621. {
  622. _TRACE(TRACE_DEBUGGING,"eventselect failed");
  623. goto CloseAndExitOnError;
  624. }
  625. return( TRUE );
  626. CloseAndExitOnError:
  627. _TRACE(TRACE_DEBUGGING,"closing listen socket");
  628. closesocket( m_sFamily[iFamIdx].sListenSocket );
  629. m_sFamily[iFamIdx].sListenSocket = INVALID_SOCKET;
  630. ExitOnError:
  631. dwCode = WSAGetLastError();
  632. if (dwCode != ERROR_SUCCESS )
  633. {
  634. _TRACE(TRACE_DEBUGGING,L"Error in CreateSocket : %d ",dwCode);
  635. DecodeWSAErrorCodes( dwCode , m_dwTelnetPort );
  636. }
  637. return( FALSE );
  638. }
  639. bool
  640. CTelnetService::InitTCPIP( void )
  641. {
  642. WSADATA WSAData;
  643. DWORD dwStatus;
  644. WORD wVersionReqd;
  645. bool bOkay4 = false, bOkay6 = false;
  646. DWORD dwSize = 0, dwResult;
  647. PCHAR szIpAddr = NULL;
  648. struct addrinfo *ai, hints;
  649. char buff[MAX_STRING_LENGTH];
  650. wVersionReqd = MAKEWORD( 2, 0 );
  651. dwStatus = WSAStartup( wVersionReqd, &WSAData );
  652. if ( dwStatus )
  653. {
  654. DecodeSocketStartupErrorCodes( dwStatus ); //It does tracing and loggin
  655. return FALSE;
  656. }
  657. if ( ( m_sFamily[IPV4_FAMILY].SocketAcceptEvent = WSACreateEvent() ) == WSA_INVALID_EVENT )
  658. {
  659. goto ExitOnError;
  660. }
  661. if ( ( m_sFamily[IPV6_FAMILY].SocketAcceptEvent = WSACreateEvent() ) == WSA_INVALID_EVENT )
  662. {
  663. goto ExitOnError;
  664. }
  665. SfuZeroMemory(&hints, sizeof(hints));
  666. hints.ai_flags = AI_PASSIVE;
  667. _ltoa(m_dwTelnetPort,buff,10);
  668. dwResult = getaddrinfo(NULL,buff , &hints, &ai);
  669. if (dwResult)
  670. {
  671. _TRACE(TRACE_DEBUGGING,L"Error in getaddrinfo() : %d",dwResult);
  672. goto ExitOnError;
  673. }
  674. while (ai)
  675. {
  676. switch (ai->ai_family)
  677. {
  678. case AF_INET:
  679. if (!bOkay4)
  680. {
  681. bOkay4 = CreateSocket(IPV4_FAMILY);
  682. _TRACE(TRACE_DEBUGGING,L"Creating IPV4 socket. bOkay4 = %d ",(int)bOkay4);
  683. }
  684. break;
  685. case AF_INET6:
  686. if (!bOkay6)
  687. {
  688. bOkay6 = CreateSocket(IPV6_FAMILY);
  689. _TRACE(TRACE_DEBUGGING,L"Creating IPV6 socketb. bOkay6 = %d ",(int)bOkay6);
  690. }
  691. break;
  692. default:
  693. _TRACE(TRACE_DEBUGGING,L"Error : Returned none of the families");
  694. break;
  695. }
  696. ai= ai->ai_next;
  697. }
  698. if ( !bOkay4 && !bOkay6 )
  699. {
  700. return( FALSE );
  701. }
  702. return( TRUE );
  703. ExitOnError:
  704. DecodeWSAErrorCodes( WSAGetLastError() );
  705. return( FALSE );
  706. }
  707. bool
  708. CTelnetService::CreateNewIoCompletionPort( DWORD cSimultaneousClients )
  709. {
  710. _chVERIFY2( m_hCompletionPort = CreateIoCompletionPort(
  711. INVALID_HANDLE_VALUE, NULL, 1, cSimultaneousClients ) );
  712. return( m_hCompletionPort != NULL );
  713. }
  714. bool
  715. CTelnetService::AssociateDeviceWithCompletionPort ( HANDLE hCompPort,
  716. HANDLE hDevice,
  717. DWORD_PTR dwCompKey
  718. )
  719. {
  720. _chASSERT( hCompPort != NULL );
  721. _chASSERT( hDevice != NULL );
  722. if ( ( hCompPort == NULL ) || ( hDevice == NULL ) )
  723. {
  724. return FALSE;
  725. }
  726. HANDLE h = NULL;
  727. _chVERIFY2( h = CreateIoCompletionPort( hDevice, hCompPort, dwCompKey, 1 ));
  728. if ( h != hCompPort)
  729. {
  730. DWORD dwErr = GetLastError();
  731. _TRACE( TRACE_DEBUGGING, "AssociateDeviceWithCompletionPort() -- 0x%1x", dwErr );
  732. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_FAILASSOCIATEPORT, dwErr );
  733. }
  734. return( h == hCompPort );
  735. }
  736. bool
  737. CTelnetService::StartThreads( void )
  738. {
  739. DWORD dwThreadId;
  740. if ( !CreateNewIoCompletionPort( 1 ) )
  741. {
  742. return( FALSE );
  743. }
  744. // if( m_hIPCThread != NULL )
  745. // {
  746. // TELNET_SYNC_CLOSE_HANDLE( m_hIPCThread );
  747. // m_hIPCThread = NULL;
  748. // }
  749. _chVERIFY2( m_hIPCThread = CreateThread( NULL, 0, DoIPCWithClients, ( LPVOID ) g_pTelnetService, 0, &dwThreadId ) );
  750. if ( !m_hIPCThread )
  751. {
  752. return( FALSE );
  753. }
  754. return( TRUE );
  755. }
  756. bool
  757. CTelnetService::GetRegistryValues( void )
  758. {
  759. HKEY hk = NULL;
  760. DWORD dwDisp = 0;
  761. if ( TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_PARAMS_KEY, NULL, NULL,
  762. REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL, &hk, &dwDisp, 0 ) )
  763. {
  764. return( FALSE );
  765. }
  766. if ( !GetRegistryDW( hk, NULL, L"MaxConnections", &m_dwMaxConnections,
  767. DEFAULT_MAX_CONNECTIONS,FALSE ) )
  768. {
  769. return( FALSE );
  770. }
  771. else
  772. {
  773. CQList->m_dwMaxUnauthenticatedConnections = m_dwMaxConnections;
  774. }
  775. if ( !GetRegistryDW( hk, NULL, L"TelnetPort", &m_dwTelnetPort,
  776. DEFAULT_TELNET_PORT,FALSE ) )
  777. {
  778. return( FALSE );
  779. }
  780. if ( !GetRegistryString( hk, NULL, L"ListenToSpecificIpAddr", &m_pszIpAddrToListenOn,
  781. DEFAULT_IP_ADDR,FALSE ) )
  782. {
  783. return( FALSE );
  784. }
  785. RegCloseKey( hk );
  786. return( TRUE );
  787. }
  788. bool
  789. CTelnetService::HandleChangeInRegKeys( )
  790. {
  791. HKEY hk = NULL;
  792. DWORD dwNewTelnetPort = 0;
  793. DWORD dwNewMaxConnections = 0;
  794. DWORD dwMaxFileSize = 0;
  795. DWORD dwLogToFile = 0;
  796. LPWSTR pszNewLogFile = NULL;
  797. LPWSTR pszNewIpAddr = NULL;
  798. DWORD dwDisp = 0;
  799. if ( TnSecureRegCreateKeyEx( HKEY_LOCAL_MACHINE, REG_PARAMS_KEY, NULL, NULL,
  800. REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED , NULL, &hk, &dwDisp, 0 ) )
  801. {
  802. return( FALSE );
  803. }
  804. if ( !GetRegistryDW( hk, NULL, L"TelnetPort", &dwNewTelnetPort,
  805. DEFAULT_TELNET_PORT,FALSE ) )
  806. {
  807. return( FALSE );
  808. }
  809. if ( !GetRegistryDW( hk, NULL, L"MaxConnections", &dwNewMaxConnections,
  810. DEFAULT_MAX_CONNECTIONS,FALSE ) )
  811. {
  812. return( FALSE );
  813. }
  814. if ( !GetRegistryDW( hk, NULL, LOGFILESIZE, &dwMaxFileSize, DEFAULT_LOGFILESIZE,FALSE ) )
  815. {
  816. return( FALSE );
  817. }
  818. if ( !GetRegistryDW( hk, NULL, L"LogToFile", &dwLogToFile, DEFAULT_LOGTOFILE,FALSE ) )
  819. {
  820. return( FALSE );
  821. }
  822. if ( !GetRegistryString( hk, NULL, L"LogFile", &pszNewLogFile, DEFAULT_LOGFILE,FALSE ) )
  823. {
  824. return( FALSE );
  825. }
  826. if ( !GetRegistryString( hk, NULL, L"ListenToSpecificIpAddr", &pszNewIpAddr,
  827. DEFAULT_IP_ADDR,FALSE ) )
  828. {
  829. return( FALSE );
  830. }
  831. SetNewRegKeyValues( dwNewTelnetPort, dwNewMaxConnections,
  832. dwMaxFileSize, pszNewLogFile, pszNewIpAddr, dwLogToFile );
  833. RegCloseKey( hk );
  834. return( TRUE );
  835. }
  836. //------------------------------------------------------------------------------
  837. //this is the thread which waits on the telnet port for any new connections
  838. //and also for any change in the reg keys
  839. //------------------------------------------------------------------------------
  840. bool
  841. CTelnetService::ListenerThread( )
  842. {
  843. BOOL bContinue = true;
  844. HANDLE eventArray[ 4 ];
  845. DWORD dwWaitRet = 0;
  846. SOCKET sSocket = INVALID_SOCKET;
  847. INT iFamIdx =IPV4_FAMILY;
  848. //DebugBreak();
  849. /*++
  850. MSRC issue 567.
  851. To generate random numbers, use Crypt...() functions. Acquire a crypt context at the beginning of
  852. ListenerThread and release the context at the end of the thread. If acquiring the context fails,
  853. the service fails to start since we do not want to continue with weak pipe names.
  854. initialize the random number generator
  855. --*/
  856. if (!CryptAcquireContext(&g_hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT))
  857. {
  858. _TRACE(TRACE_DEBUGGING,L"Acquiring crypt context failed with error %d",GetLastError());
  859. return FALSE;
  860. }
  861. if ( !Init() )
  862. {
  863. LogEvent( EVENTLOG_ERROR_TYPE, MSG_FAILEDTOINITIALIZE, _T("") );
  864. return FALSE;
  865. }
  866. // BaskarK: Set the error mode for this process to "do not disturb" so that all our children will inherit and will
  867. // not stop the stresss, dead on its tracks...
  868. SetErrorMode(
  869. SEM_FAILCRITICALERRORS |
  870. SEM_NOGPFAULTERRORBOX |
  871. SEM_NOALIGNMENTFAULTEXCEPT |
  872. SEM_NOOPENFILEERRORBOX);
  873. eventArray[ SOCKET_CLOSE_EVENT ] = g_pTelnetService->m_hSocketCloseEvent;
  874. eventArray[ FD_ACCEPT_EVENT_0 ] = g_pTelnetService->m_sFamily[IPV4_FAMILY].SocketAcceptEvent;
  875. eventArray[ REG_CHANGE_EVENT ] = g_pTelnetService->m_hRegChangeEvent;
  876. eventArray[ FD_ACCEPT_EVENT_1 ] = g_pTelnetService->m_sFamily[IPV6_FAMILY].SocketAcceptEvent;
  877. _Module.SetServiceStatus(SERVICE_RUNNING);
  878. _TRACE( TRACE_DEBUGGING, "ListenerThread() -- Enter" );
  879. while ( bContinue )
  880. {
  881. //Refer to doc on select for FD_ZERO, FD_SET etc.
  882. iFamIdx = IPV4_FAMILY;
  883. dwWaitRet = WaitForMultipleObjects ( 4, eventArray, FALSE, INFINITE );
  884. switch (dwWaitRet)
  885. {
  886. case FD_ACCEPT_EVENT_1:
  887. iFamIdx = IPV6_FAMILY;
  888. // fall through
  889. case FD_ACCEPT_EVENT_0:
  890. // NOTE: ***********************************************
  891. // The only exit point out of this case statement should be
  892. // through FD_ACCEPT_EVENT_CLEANUP only. Otherwise, you will
  893. // cause serious leak of sockets inthe tlntsvr - BaskarK
  894. {
  895. INT iSize;
  896. struct sockaddr_storage ss;
  897. WSANETWORKEVENTS wsaNetEvents;
  898. bool bSendMessage = false;
  899. struct sockaddr_storage saddrPeer;
  900. char szIPAddr[ SMALL_STRING ];
  901. DWORD dwPid = 0;
  902. HANDLE hWritePipe = NULL;
  903. // _TRACE( TRACE_DEBUGGING, " FD_ACCEPT_EVENT " );
  904. wsaNetEvents.lNetworkEvents = 0;
  905. if ( WSAEnumNetworkEvents( g_pTelnetService->m_sFamily[iFamIdx].sListenSocket, g_pTelnetService->m_sFamily[iFamIdx].SocketAcceptEvent,
  906. &wsaNetEvents ) == SOCKET_ERROR )
  907. {
  908. DWORD dwErr = WSAGetLastError();
  909. _TRACE( TRACE_DEBUGGING, " Error -- WSAEnumNetworkEvents-- 0x%x ", dwErr);
  910. DecodeWSAErrorCodes( dwErr );
  911. goto FD_ACCEPT_EVENT_CLEANUP;
  912. }
  913. if ( wsaNetEvents.lNetworkEvents & FD_ACCEPT )
  914. {
  915. if (sSocket != INVALID_SOCKET)
  916. {
  917. // shutdown(sSocket, SD_BOTH);
  918. closesocket(sSocket);
  919. sSocket = INVALID_SOCKET;
  920. }
  921. iSize = sizeof(ss);
  922. __try
  923. {
  924. sSocket = accept( g_pTelnetService->m_sFamily[iFamIdx].sListenSocket,(struct sockaddr*) &ss, &iSize );
  925. }
  926. __except(EXCEPTION_EXECUTE_HANDLER)
  927. {
  928. sSocket = INVALID_SOCKET;
  929. WSASetLastError(WSAEFAULT);
  930. }
  931. if (sSocket == INVALID_SOCKET)
  932. {
  933. DWORD dwErr = WSAGetLastError();
  934. _TRACE( TRACE_DEBUGGING, " Error -- accept -- %d ", dwErr);
  935. switch (dwErr)
  936. {
  937. case WSAEWOULDBLOCK: // non blocking socket so just loop back to the wait again
  938. WSASetEvent( g_pTelnetService->m_sFamily[iFamIdx].SocketAcceptEvent );
  939. break;
  940. default:
  941. // DebugBreak();
  942. DecodeWSAErrorCodes( dwErr );
  943. }
  944. }
  945. else
  946. {
  947. CClientInfo *new_client = NULL;
  948. _TRACE( TRACE_DEBUGGING, "accept succeded... sSocket = %d",(DWORD)sSocket );
  949. // Set the option to don't linger around
  950. // Similarly, not to reuse address;
  951. {
  952. int value_to_set = FALSE;
  953. setsockopt(
  954. sSocket,
  955. SOL_SOCKET,
  956. SO_LINGER,
  957. ( char * )&value_to_set,
  958. sizeof( value_to_set )
  959. );
  960. value_to_set = TRUE;
  961. setsockopt(
  962. sSocket,
  963. SOL_SOCKET,
  964. SO_EXCLUSIVEADDRUSE,
  965. ( char * )&value_to_set,
  966. sizeof( value_to_set )
  967. );
  968. }
  969. if (g_pTelnetService->m_sFamily[iFamIdx].SocketAcceptEvent == WSA_INVALID_EVENT)
  970. {
  971. goto FD_ACCEPT_EVENT_CLEANUP;
  972. }
  973. //Disassociate the default association to the event
  974. _chVERIFY2( WSAEventSelect( sSocket,
  975. g_pTelnetService->m_sFamily[iFamIdx].SocketAcceptEvent, 0 ) != SOCKET_ERROR );
  976. LONG lSrvStat = SERVER_RUNNING;
  977. lSrvStat = InterlockedCompareExchange( &g_pTelnetService->m_lServerState,
  978. SERVER_PAUSED, SERVER_PAUSED );
  979. if ( lSrvStat == SERVER_PAUSED )
  980. {
  981. CHAR szMessageBuffer[ MAX_STRING_LENGTH + 1 ];
  982. if (LoadStringA( g_hInstRes, IDS_SERVICE_PAUSED, szMessageBuffer, MAX_STRING_LENGTH))
  983. {
  984. InformTheClient( sSocket, szMessageBuffer );
  985. }
  986. shutdown( sSocket, SD_BOTH );
  987. goto FD_ACCEPT_EVENT_CLEANUP;
  988. }
  989. else
  990. {
  991. /*++
  992. Get IP address of the client which requested the connection. This will
  993. also be stored in a queue entry. We put a limit on maximum number
  994. of unauthenticated connections that can be created from one IP address.
  995. --*/
  996. iSize = sizeof( saddrPeer );
  997. SfuZeroMemory( &saddrPeer, iSize );
  998. if ( getpeername( sSocket, ( struct sockaddr * ) &saddrPeer, &iSize ) == SOCKET_ERROR )
  999. {
  1000. _TRACE(TRACE_DEBUGGING, "getpeername error : %d",GetLastError());
  1001. goto FD_ACCEPT_EVENT_CLEANUP;
  1002. }
  1003. getnameinfo((SOCKADDR*)&saddrPeer, iSize, szIPAddr, SMALL_STRING,
  1004. NULL, 0, NI_NUMERICHOST);
  1005. _TRACE(TRACE_DEBUGGING, "getpeername : %s",szIPAddr);
  1006. if (! CQList->OkToProceedWithThisClient(szIPAddr))
  1007. {
  1008. CHAR szMessageBuffer[ MAX_STRING_LENGTH + 1 ];
  1009. //Denying connection due to limit on maximum number of
  1010. //unauthenticated connections per IP
  1011. _TRACE( TRACE_DEBUGGING, "Max Unauthenticated connections reached" );
  1012. _TRACE(TRACE_DEBUGGING, "%s, %d cannot be added",szIPAddr, dwPid);
  1013. if (LoadStringA( g_hInstRes, IDS_MAX_IPLIMIT_REACHED, szMessageBuffer, MAX_STRING_LENGTH ))
  1014. {
  1015. InformTheClient( sSocket, szMessageBuffer ); // Don't care about its success, continue
  1016. _TRACE(TRACE_DEBUGGING, "shutting down socket for pid %d, socket %d", dwPid,(DWORD)sSocket);
  1017. }
  1018. shutdown(sSocket, SD_BOTH);
  1019. goto FD_ACCEPT_EVENT_CLEANUP;
  1020. }
  1021. /*++
  1022. CreateClient will return pid and pipehandle of the session
  1023. process that is created. this will be used by the queue object,
  1024. which stores information about all the sessions that are in
  1025. unauthenticated state.
  1026. Whenever a new session is created, it's info will be stored as
  1027. a queue entry in CQList.
  1028. --*/
  1029. if ( !CreateClient( sSocket, &dwPid, &hWritePipe, &new_client) )
  1030. {
  1031. CHAR szMessageBuffer[ MAX_STRING_LENGTH + 1 ];
  1032. _TRACE( TRACE_DEBUGGING, "new Telnet Client failed" );
  1033. if (LoadStringA( g_hInstRes, IDS_ERR_NEW_SESS_INIT, szMessageBuffer, MAX_STRING_LENGTH ))
  1034. {
  1035. InformTheClient( sSocket, szMessageBuffer ); // Don't care if this fails, we have to continue
  1036. }
  1037. goto FD_ACCEPT_EVENT_CLEANUP;
  1038. }
  1039. else
  1040. {
  1041. sSocket = INVALID_SOCKET; // From now onwards, we will reference this through the new_client class.
  1042. }
  1043. // hWritePipe will be NULL if IssueReadFromPipe fails in the CreateClient
  1044. // and hence we do StopServicingClient, so don't need to add the entry in a
  1045. // queue.
  1046. if (!hWritePipe)
  1047. goto FD_ACCEPT_EVENT_CLEANUP;
  1048. _TRACE( TRACE_DEBUGGING, "CreateClient success : %d",dwPid);
  1049. /*++
  1050. Add the session's information to the queue. CanIAdd will return FALSE
  1051. when the number of unauthenticated connections from the IP address
  1052. have already reached the limit, or when the queue is full.
  1053. In these cases, we notify the requesting client
  1054. that no more connections can be added. Otherwise, the new connection request
  1055. entry is added into the queue and CanIAdd returns TRUE.
  1056. In case of IPLimitReached or QueueFull,
  1057. we send the PipeHandle for that session back here so that we
  1058. can notify that session and tell that session to terminate itself. In these cases,
  1059. the flag bSendFlag is set to TRUE.
  1060. --*/
  1061. if (!CQList->WasTheClientAdded(dwPid,szIPAddr, &hWritePipe, &bSendMessage))
  1062. {
  1063. //Denying connection due to limit on maximum number of
  1064. //unauthenticated connections per IP
  1065. CHAR szMessageBuffer[ MAX_STRING_LENGTH + 1 ];
  1066. _TRACE( TRACE_DEBUGGING, "Max Unauthenticated connections reached" );
  1067. _TRACE(TRACE_DEBUGGING, "%s, %d cannot be added",szIPAddr, dwPid);
  1068. if (LoadStringA( g_hInstRes, IDS_MAX_IPLIMIT_REACHED, szMessageBuffer, MAX_STRING_LENGTH ))
  1069. {
  1070. InformTheClient( new_client->sSocket, szMessageBuffer ); // Don't care about its success, continue
  1071. _TRACE(TRACE_DEBUGGING, "shutting down socket for pid %d, socket %d", dwPid,(DWORD)new_client->sSocket);
  1072. }
  1073. }
  1074. if (bSendMessage)
  1075. {
  1076. //send message to session telling it to terminate itself
  1077. bSendMessage = false;
  1078. _TRACE(TRACE_DEBUGGING, "Asking the session %d to shutdown on socket %d",dwPid, (DWORD)sSocket);
  1079. CQList->FreeEntry(dwPid);
  1080. AskSessionToShutdown(hWritePipe, GO_DOWN);
  1081. // shutdown(sSocket, SD_BOTH);
  1082. }
  1083. // FALL back to FD_ACCEPT_EVENT_CLEANUP will clean/close the socket..
  1084. TELNET_CLOSE_HANDLE(hWritePipe);
  1085. }
  1086. }
  1087. }
  1088. }
  1089. FD_ACCEPT_EVENT_CLEANUP: ;
  1090. if (sSocket != INVALID_SOCKET)
  1091. {
  1092. // shutdown(sSocket, SD_BOTH);
  1093. closesocket(sSocket);
  1094. sSocket = INVALID_SOCKET;
  1095. }
  1096. break;
  1097. case SOCKET_CLOSE_EVENT:
  1098. _TRACE( TRACE_DEBUGGING, " SOCKET_CLOSE_EVENT " );
  1099. bContinue = false;
  1100. break;
  1101. case REG_CHANGE_EVENT:
  1102. _TRACE( TRACE_DEBUGGING, " REG_CHANGE_EVENT " );
  1103. HandleChangeInRegKeys( );
  1104. ResetEvent( g_pTelnetService->m_hRegChangeEvent );
  1105. RegisterForNotification();
  1106. break;
  1107. default:
  1108. _TRACE( TRACE_DEBUGGING, " Error -- WaitForMultipleObjects " );
  1109. // DebugBreak();
  1110. if ( dwWaitRet == WAIT_FAILED )
  1111. {
  1112. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, 0, GetLastError() );
  1113. }
  1114. // bContinue = false; don't breakout of the loop,
  1115. // reject invalid requests (due to DOS attacks) keep continuing -- BaskarK
  1116. break;
  1117. }
  1118. }
  1119. if (g_pTelnetService->m_hReadConfigKey)
  1120. RegCloseKey( g_pTelnetService->m_hReadConfigKey );
  1121. TELNET_CLOSE_HANDLE( g_pTelnetService->m_hRegChangeEvent );
  1122. //Socket related clean up
  1123. if (g_pTelnetService->m_sFamily[IPV4_FAMILY].sListenSocket != INVALID_SOCKET)
  1124. {
  1125. closesocket( g_pTelnetService->m_sFamily[IPV4_FAMILY].sListenSocket );
  1126. g_pTelnetService->m_sFamily[IPV4_FAMILY].sListenSocket = INVALID_SOCKET;
  1127. }
  1128. if (g_pTelnetService->m_sFamily[IPV6_FAMILY].sListenSocket != INVALID_SOCKET)
  1129. {
  1130. closesocket( g_pTelnetService->m_sFamily[IPV6_FAMILY].sListenSocket );
  1131. g_pTelnetService->m_sFamily[IPV6_FAMILY].sListenSocket = INVALID_SOCKET;
  1132. }
  1133. TELNET_CLOSE_HANDLE( g_pTelnetService->m_hSocketCloseEvent );
  1134. if (m_sFamily[IPV4_FAMILY].SocketAcceptEvent)
  1135. {
  1136. WSACloseEvent( m_sFamily[IPV4_FAMILY].SocketAcceptEvent );
  1137. }
  1138. if (m_sFamily[IPV6_FAMILY].SocketAcceptEvent)
  1139. {
  1140. WSACloseEvent( m_sFamily[IPV6_FAMILY].SocketAcceptEvent );
  1141. }
  1142. if(g_hProv)
  1143. {
  1144. CryptReleaseContext(g_hProv,0);
  1145. g_hProv = NULL;
  1146. }
  1147. WSACleanup();
  1148. return( TRUE );
  1149. }
  1150. bool
  1151. CTelnetService::IssueLicense( bool bIsIssued, CClientInfo *pClient )
  1152. {
  1153. UCHAR ucMsg = LICENSE_NOT_AVAILABLE;
  1154. if ( bIsIssued )
  1155. {
  1156. ucMsg = LICENSE_AVAILABLE;
  1157. }
  1158. if ( !WriteToPipe( pClient->hWritingPipe, ucMsg, &( m_oWriteToPipe ) ) )
  1159. {
  1160. return( FALSE );
  1161. }
  1162. return( TRUE );
  1163. }
  1164. bool
  1165. CTelnetService::GetLicenseForWorkStation( SOCKET sSocket )
  1166. {
  1167. DWORD dwIndex = 0;
  1168. bool bRetVal = FALSE;
  1169. struct sockaddr_storage saddrPeer;
  1170. socklen_t slSize = sizeof( saddrPeer );
  1171. SfuZeroMemory( &saddrPeer, slSize );
  1172. if ( getpeername( sSocket, ( struct sockaddr * ) &saddrPeer, &slSize ) == SOCKET_ERROR )
  1173. {
  1174. goto GetLicenseForWorkStationAbort;
  1175. }
  1176. // Don't compare ports
  1177. SS_PORT(&saddrPeer) = 0;
  1178. for ( dwIndex = 0; dwIndex < m_dwNoOfWorkstations; dwIndex++ )
  1179. {
  1180. if ( !memcmp(&m_pssWorkstationList[ dwIndex ], &saddrPeer, slSize ))
  1181. {
  1182. bRetVal = TRUE;
  1183. goto GetLicenseForWorkStationAbort;
  1184. }
  1185. }
  1186. if ( m_dwNoOfWorkstations < DEFAULT_LICENSES_FOR_NTWKSTA )
  1187. {
  1188. m_pssWorkstationList[ m_dwNoOfWorkstations++ ] = saddrPeer;
  1189. bRetVal = TRUE;
  1190. }
  1191. GetLicenseForWorkStationAbort:
  1192. return( bRetVal );
  1193. }
  1194. bool
  1195. CTelnetService::CheckLicense( bool *bIsIssued, CClientInfo *pClient )
  1196. {
  1197. #if DBG
  1198. CHAR szDebug[MAX_STRING_LENGTH * 3];
  1199. #endif
  1200. bool bSuccess = false;
  1201. *bIsIssued = false; //Not issued
  1202. if ( !pClient )
  1203. {
  1204. return( FALSE );
  1205. }
  1206. _TRACE(TRACE_DEBUGGING,L"In CheckLicense");
  1207. if ( m_dwNumOfActiveConnections >= m_dwMaxConnections )
  1208. {
  1209. static CHAR ansi_g_szMaxConnectionsReached[ MAX_STRING_LENGTH ] = { 0};
  1210. if ('\0' == ansi_g_szMaxConnectionsReached[0])
  1211. {
  1212. wsprintfA( ansi_g_szMaxConnectionsReached, "%lS", g_szMaxConnectionsReached ); // NO over flow here, Baskar
  1213. }
  1214. LogEvent( EVENTLOG_INFORMATION_TYPE, MSG_MAXCONNECTIONS, _T(" ") );
  1215. _TRACE(TRACE_DEBUGGING,L"CheckLicense : Max Conn reached. Freeing entry for %d",pClient->dwPid);
  1216. if ( InformTheClient( pClient->sSocket, ansi_g_szMaxConnectionsReached ) )
  1217. {
  1218. bSuccess = true;
  1219. }
  1220. goto FREE_ENTRY_AND_GET_OUT;
  1221. }
  1222. //if it is an NT Workstation
  1223. if ( m_bIsWorkStation )
  1224. {
  1225. _TRACE(TRACE_DEBUGGING,L"CheckLicense : Getting license for workstation");
  1226. if ( !GetLicenseForWorkStation( pClient->sSocket ) )
  1227. {
  1228. static CHAR wksta_error_msg[ sizeof(NTWKSTA_LICENSE_LIMIT) + sizeof(TERMINATE) + 1] = { 0};
  1229. if ('\0' == wksta_error_msg[0])
  1230. {
  1231. wsprintfA( wksta_error_msg, "%s%s", NTWKSTA_LICENSE_LIMIT, TERMINATE); // NO over flow here, Baskar
  1232. }
  1233. if ( InformTheClient( pClient->sSocket, wksta_error_msg ) )
  1234. {
  1235. bSuccess = true;
  1236. }
  1237. goto FREE_ENTRY_AND_GET_OUT;
  1238. }
  1239. else
  1240. {
  1241. bSuccess=true;
  1242. }
  1243. }
  1244. else
  1245. {
  1246. NT_LS_DATA NtLSData = { 0};
  1247. CHAR usrnam[2*MAX_PATH + 1+ 1] = { 0}; // User + domain + \ + NULL
  1248. LS_STATUS_CODE Status = { 0};
  1249. _TRACE(TRACE_DEBUGGING,L"CheckLicense : License for server");
  1250. _snprintf(usrnam, 2*MAX_PATH + 1, "%s\\%s", pClient->szDomain, pClient->szUserName);
  1251. _TRACE(TRACE_DEBUGGING,L"CheckLicense : user name is %s",usrnam);
  1252. NtLSData.DataType = NT_LS_USER_NAME;
  1253. NtLSData.Data = usrnam;
  1254. NtLSData.IsAdmin = FALSE;
  1255. {
  1256. static CHAR szVersion[16] = { 0};
  1257. {
  1258. static OSVERSIONINFO osVersionInfo = { 0};
  1259. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1260. if (0 == szVersion[0])
  1261. {
  1262. if ( !GetVersionEx( &osVersionInfo ) )
  1263. {
  1264. _TRACE( TRACE_DEBUGGING, "Error: GetVersionEx()" );
  1265. }
  1266. _snprintf( szVersion, (sizeof(szVersion) - 1), "%d.%d", osVersionInfo.dwMajorVersion,
  1267. osVersionInfo.dwMinorVersion );
  1268. }
  1269. }
  1270. Status = NtLicenseRequestA( "SMBServer", szVersion, &( pClient->m_hLicense), &NtLSData);
  1271. }
  1272. #if DBG
  1273. sprintf(szDebug,"License is %d. Status is %d \n",(DWORD)pClient->m_hLicense,Status);
  1274. OutputDebugStringA(szDebug);
  1275. #endif
  1276. switch ( Status)
  1277. {
  1278. case LS_SUCCESS :
  1279. // go ahead and do what you want
  1280. _TRACE(TRACE_DEBUGGING,L"CheckLicense : acquired license %d",(DWORD)pClient->m_hLicense);
  1281. bSuccess = true;
  1282. break;
  1283. // case LS_INSUFFICIENT_UNITS :
  1284. // case LS_RESOURCES_UNAVAILABLE:
  1285. default :
  1286. pClient->m_hLicense = INVALID_LICENSE_HANDLE;
  1287. {
  1288. static CHAR server_error_msg[ sizeof(NTSVR_LICENSE_LIMIT) + sizeof(TERMINATE) + 1] = { 0};
  1289. if ('\0' == server_error_msg[0])
  1290. {
  1291. wsprintfA( server_error_msg, "%s%s", NTSVR_LICENSE_LIMIT, TERMINATE); // NO over flow here, Baskar
  1292. }
  1293. _TRACE(TRACE_DEBUGGING,L"Error in acquiring a license");
  1294. if (InformTheClient( pClient->sSocket, server_error_msg ) )
  1295. {
  1296. bSuccess = true;
  1297. }
  1298. }
  1299. goto FREE_ENTRY_AND_GET_OUT;
  1300. }
  1301. }
  1302. if (bSuccess)
  1303. {
  1304. *bIsIssued = true;
  1305. //An active session is allowed now
  1306. m_dwNumOfActiveConnections++ ;
  1307. pClient->bLicenseIssued = true;
  1308. }
  1309. FREE_ENTRY_AND_GET_OUT:
  1310. CQList->FreeEntry(pClient->dwPid); // this client shoudl no longer be in the unauth list.
  1311. _TRACE(TRACE_DEBUGGING,L"CheckLicense : Freeing entry for %d",pClient->dwPid);
  1312. return( bSuccess );
  1313. }
  1314. void
  1315. CTelnetService::GetPathOfTheExecutable( LPTSTR *szCmdBuf )
  1316. {
  1317. DWORD length_required = wcslen( g_pszTelnetInstallPath ) + wcslen( DEFAULT_SCRAPER_PATH ) + 2; // One for \ and one more for NULL termination
  1318. LPTSTR lpszDefaultScraperFullPathName = new TCHAR[ length_required ];
  1319. *szCmdBuf = NULL; // First init this to NULL, so upon a failure the caller can check on this ptr != NULL; this function is a void returnee
  1320. if ( !lpszDefaultScraperFullPathName )
  1321. return;
  1322. _snwprintf(lpszDefaultScraperFullPathName, length_required - 1, L"%s\\%s", g_pszTelnetInstallPath, DEFAULT_SCRAPER_PATH);
  1323. lpszDefaultScraperFullPathName[length_required-1] = 0; // When the buffer is full snwprintf could return non-null terminated string
  1324. AllocateNExpandEnvStrings( lpszDefaultScraperFullPathName, szCmdBuf );
  1325. delete [] lpszDefaultScraperFullPathName;
  1326. return;
  1327. }
  1328. bool
  1329. CTelnetService::CreateSessionProcess( HANDLE hStdinPipe, HANDLE hStdoutPipe,
  1330. DWORD *dwProcessId, HANDLE *hProcess,
  1331. HWINSTA *window_station, HDESK *desktop)
  1332. {
  1333. PROCESS_INFORMATION pi = { 0};
  1334. STARTUPINFO si = { 0};
  1335. LPWSTR szCmdBuf = NULL;
  1336. BOOL fStatus = FALSE;
  1337. bool bRetVal = false;
  1338. *hProcess = INVALID_HANDLE_VALUE;
  1339. *dwProcessId = MAXDWORD;
  1340. si.cb = sizeof(si);
  1341. GetPathOfTheExecutable( &szCmdBuf );
  1342. if (szCmdBuf) // => GetPathXxx succeeded.
  1343. {
  1344. //Let the tlntsess.exe get created on Default desktop. We will create the new desktops
  1345. //in the session
  1346. FillProcessStartupInfo( &si, hStdinPipe, hStdoutPipe, hStdoutPipe, NULL);
  1347. fStatus = CreateProcess(
  1348. NULL,
  1349. szCmdBuf,
  1350. NULL,
  1351. NULL,
  1352. TRUE,
  1353. CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE,
  1354. NULL,
  1355. NULL,
  1356. &si,
  1357. &pi
  1358. );
  1359. _chVERIFY2(fStatus) ;
  1360. if ( !fStatus )
  1361. {
  1362. #if DBG
  1363. OutputDebugStringA("BASKAR: CreateProcess fails for TlntSess.exe\n");
  1364. #endif
  1365. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_CREATEPROCESS,
  1366. GetLastError() );
  1367. goto Done;
  1368. }
  1369. }
  1370. else
  1371. {
  1372. #if DBG
  1373. OutputDebugStringA("BASKAR: GetPathOfTheExecutable, tlntsess.exe failed\n");
  1374. #endif
  1375. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_CREATEPROCESS,
  1376. ERROR_NOT_ENOUGH_MEMORY );
  1377. goto Done;
  1378. }
  1379. *hProcess = pi.hProcess;
  1380. *dwProcessId = pi.dwProcessId;
  1381. bRetVal = true;
  1382. Done:
  1383. TELNET_CLOSE_HANDLE( pi.hThread );
  1384. if(szCmdBuf)
  1385. delete [] szCmdBuf; // no longer needed
  1386. return( bRetVal);
  1387. }
  1388. bool
  1389. CTelnetService::CreateClient(
  1390. SOCKET sSocket ,
  1391. DWORD *pdwPid,
  1392. HANDLE *phWritePipe,
  1393. CClientInfo **newClientInfo
  1394. )
  1395. {
  1396. HANDLE hProcess = INVALID_HANDLE_VALUE;
  1397. bool bRetVal = FALSE;
  1398. DWORD dwErr = 0;
  1399. DWORD dwProcessId;
  1400. HANDLE hStdinPipe = NULL;
  1401. HANDLE hStdoutPipe = NULL;
  1402. HANDLE hPipeRead = NULL;
  1403. HANDLE hPipeWrite = NULL;
  1404. HWINSTA window_station = NULL;
  1405. HDESK desktop = NULL;
  1406. bool bSuccess = false;
  1407. DWORD dwExitCode = 0;
  1408. bool release_mutex = false;
  1409. PSECURITY_DESCRIPTOR psd = NULL;
  1410. *newClientInfo = NULL;
  1411. _chASSERT( sSocket );
  1412. if ( sSocket == NULL )
  1413. {
  1414. goto Done;
  1415. }
  1416. *phWritePipe = NULL;
  1417. if(!TnCreateDefaultSecDesc(&psd, GENERIC_ALL &
  1418. ~(WRITE_DAC | WRITE_OWNER | DELETE)))
  1419. {
  1420. goto Done;
  1421. }
  1422. if ( !CreateReadOrWritePipe( &hPipeRead, &hStdoutPipe, (SECURITY_DESCRIPTOR *)psd, READ_PIPE ) ||
  1423. !CreateReadOrWritePipe( &hStdinPipe, &hPipeWrite, (SECURITY_DESCRIPTOR *)psd, WRITE_PIPE ) )
  1424. {
  1425. goto ExitOnError;
  1426. }
  1427. if ( !( CreateSessionProcess( hStdinPipe, hStdoutPipe, &dwProcessId,
  1428. &hProcess, &window_station, &desktop ) ) )
  1429. {
  1430. InformTheClient( sSocket, CREATE_TLNTSESS_FAIL_MSG );
  1431. goto ExitOnError;
  1432. }
  1433. *pdwPid = dwProcessId;
  1434. _TRACE( TRACE_DEBUGGING, "new Telnet Client -- socket : %d , pid : %d", ( DWORD ) sSocket , dwProcessId);
  1435. //Make the following handles non-inheritable
  1436. _chVERIFY2( SetHandleInformation( hStdinPipe, HANDLE_FLAG_INHERIT, 0 ) );
  1437. _chVERIFY2( SetHandleInformation( hStdoutPipe, HANDLE_FLAG_INHERIT, 0 ) );
  1438. _chVERIFY2( SetHandleInformation( ( HANDLE ) sSocket, HANDLE_FLAG_INHERIT, 0 ) );
  1439. if ( !SendSocketToClient( hPipeWrite, sSocket, dwProcessId ) )
  1440. {
  1441. // Fix for HANDLE LEAK - close all handles
  1442. goto ExitOnError;
  1443. }
  1444. //The following is needed so that Count() and add() operations happen atomically
  1445. //HANDLE LEAK - maintain a bool to see if you acquired mutex - release at the end of the function???
  1446. dwErr = WaitForSingleObject( m_hSyncAllClientObjAccess, WAIT_TIME );
  1447. if ( dwErr != WAIT_OBJECT_0 )
  1448. {
  1449. //fix for HANDLE LEAK close all handles
  1450. if ( dwErr == WAIT_FAILED )
  1451. {
  1452. dwErr = GetLastError();
  1453. }
  1454. _TRACE(TRACE_DEBUGGING, "Error: WaitForSingleObject - 0x%1x", dwErr );
  1455. goto ExitOnError;
  1456. }
  1457. release_mutex = true;
  1458. _TRACE(TRACE_DEBUGGING, "Count of the ClientArray - %d, Count of sessions - %d", client_list_Count() , CQList->m_dwNumOfUnauthenticatedConnections + m_dwNumOfActiveConnections);
  1459. if ((NULL == m_hIPCThread) || (INVALID_HANDLE_VALUE == m_hIPCThread))
  1460. {
  1461. if (! StartThreads())
  1462. {
  1463. _TRACE(TRACE_DEBUGGING, "IPC Thread startup failed ? ");
  1464. goto ExitOnError;
  1465. }
  1466. }
  1467. *newClientInfo = new CClientInfo( hPipeRead, hPipeWrite,
  1468. hStdinPipe, hStdoutPipe,
  1469. sSocket, dwProcessId,
  1470. window_station, desktop);
  1471. if ( !*newClientInfo )
  1472. {
  1473. _TRACE(TRACE_DEBUGGING, "Failed to allocate memory for new client ");
  1474. goto ExitOnError;
  1475. }
  1476. // Once the handles are given to newClientInfo, its destructor will close them
  1477. hPipeRead = hPipeWrite = hStdinPipe = hStdoutPipe = INVALID_HANDLE_VALUE; // So we don't close these...
  1478. if ( !AssociateDeviceWithCompletionPort(
  1479. m_hCompletionPort, (*newClientInfo)->hReadingPipe, ( DWORD_PTR ) *newClientInfo ) )
  1480. {
  1481. goto ExitOnError;
  1482. }
  1483. if ( !client_list_Add( (PVOID)*newClientInfo ) )
  1484. {
  1485. _TRACE(TRACE_DEBUGGING, "Failed to add a new CClientInfo object ");
  1486. goto ExitOnError;
  1487. }
  1488. //We have succeeded.. if the IssueReadFromPipe() call fails, we clean up the clientinfo array and return SUCCESS
  1489. //if it succeeds, ONLY then we need to add this entry in the queue of unauthenticated connections. This check is
  1490. //made in the caller function ListenerThread(), where if pipehandle = NULL, we do not add the entry in the queue.
  1491. bRetVal=TRUE;
  1492. if ( IssueReadFromPipe( *newClientInfo ) )
  1493. {
  1494. if ( !DuplicateHandle( GetCurrentProcess(),(*newClientInfo)->hWritingPipe,
  1495. GetCurrentProcess(), phWritePipe,0,
  1496. FALSE, DUPLICATE_SAME_ACCESS) )
  1497. {
  1498. goto ExitOnError;
  1499. }
  1500. }
  1501. else
  1502. {
  1503. StopServicingClient( *newClientInfo, (BOOL)FALSE );
  1504. goto ExitOnError; // cleanup everything but the socket passed. by falling through
  1505. }
  1506. goto Done;
  1507. ExitOnError:
  1508. if (*newClientInfo)
  1509. {
  1510. (*newClientInfo)->sSocket = INVALID_SOCKET; // So that the destructor below doesn't close this and cause accept to blow-up in listener thread - VadimE's dll found this, Baskar
  1511. delete *newClientInfo;
  1512. *newClientInfo = NULL;
  1513. }
  1514. else
  1515. {
  1516. TELNET_SYNC_CLOSE_HANDLE(hStdinPipe);
  1517. TELNET_SYNC_CLOSE_HANDLE(hStdoutPipe);
  1518. TELNET_SYNC_CLOSE_HANDLE(hPipeRead);
  1519. TELNET_SYNC_CLOSE_HANDLE(hPipeWrite);
  1520. }
  1521. Done:
  1522. if (release_mutex)
  1523. {
  1524. ReleaseMutex( m_hSyncAllClientObjAccess );
  1525. }
  1526. if(psd)
  1527. {
  1528. free(psd);
  1529. }
  1530. TELNET_CLOSE_HANDLE( hProcess );
  1531. return(bRetVal);
  1532. }
  1533. bool
  1534. CTelnetService::IssueReadAgain( CClientInfo *pClientInfo )
  1535. {
  1536. if (!pClientInfo->m_ReadFromPipeBuffer)
  1537. {
  1538. return(FALSE);
  1539. }
  1540. UCHAR *pucReadBuffer = pClientInfo->m_ReadFromPipeBuffer;
  1541. if ( !pucReadBuffer )
  1542. {
  1543. return( FALSE );
  1544. }
  1545. pucReadBuffer++; //Move past the message type
  1546. //Extract Size of rest of the meesage
  1547. memcpy( &( pClientInfo->m_dwRequestedSize ), pucReadBuffer,
  1548. sizeof( DWORD ) ); // NO overflow, Baskar
  1549. pucReadBuffer = new UCHAR[ pClientInfo->m_dwRequestedSize
  1550. + IPC_HEADER_SIZE ];
  1551. if ( !pucReadBuffer )
  1552. {
  1553. return( FALSE );
  1554. }
  1555. memcpy( pucReadBuffer, ( pClientInfo->m_ReadFromPipeBuffer ),
  1556. IPC_HEADER_SIZE ); // No overflow, Baskar
  1557. delete[] ( pClientInfo->m_ReadFromPipeBuffer );
  1558. pClientInfo->m_ReadFromPipeBuffer = NULL;
  1559. pClientInfo->m_ReadFromPipeBuffer = pucReadBuffer;
  1560. //position the pointer so that rest of the message is read in to
  1561. //proper place
  1562. pClientInfo->m_dwPosition = IPC_HEADER_SIZE;
  1563. return( IssueReadFromPipe( pClientInfo ) );
  1564. }
  1565. //Even if Read file finishes synchronously, we are intimated through the IO
  1566. // completion port. So no need to handle that case
  1567. bool
  1568. CTelnetService::IssueReadFromPipe( CClientInfo *pClientInfo )
  1569. {
  1570. bool bRetVal = TRUE;
  1571. DWORD dwReceivedDataSize;
  1572. if ( !pClientInfo->hReadingPipe || !pClientInfo->m_ReadFromPipeBuffer )
  1573. {
  1574. return( FALSE );
  1575. }
  1576. UCHAR *pucReadBuffer = pClientInfo->m_ReadFromPipeBuffer +
  1577. pClientInfo->m_dwPosition;
  1578. if ( !ReadFile( pClientInfo->hReadingPipe, pucReadBuffer,
  1579. pClientInfo->m_dwRequestedSize, &dwReceivedDataSize,
  1580. &m_oReadFromPipe ) )
  1581. {
  1582. DWORD dwError = 0;
  1583. dwError = GetLastError( );
  1584. if ( dwError == ERROR_MORE_DATA )
  1585. {
  1586. //We reach here just in case it synchronously finishes
  1587. //with this error.
  1588. }
  1589. else if ( dwError != ERROR_IO_PENDING )
  1590. {
  1591. _TRACE( TRACE_DEBUGGING, " Error: ReadFile -- 0x%1x ", dwError );
  1592. bRetVal = FALSE;
  1593. }
  1594. }
  1595. else
  1596. {
  1597. //Read is completed synchronously by chance. It was actually
  1598. //an async call. All synchronously completed calls are also reported
  1599. //through the IO completion port
  1600. }
  1601. return bRetVal;
  1602. }
  1603. bool
  1604. CTelnetService::SendSocketToClient( HANDLE hPipeWrite,
  1605. SOCKET sSocket, DWORD dwPId )
  1606. {
  1607. _chASSERT( sSocket );
  1608. _chASSERT( hPipeWrite );
  1609. if ( !sSocket || !hPipeWrite )
  1610. {
  1611. return FALSE;
  1612. }
  1613. WSAPROTOCOL_INFO protocolInfo;
  1614. if ( WSADuplicateSocket( sSocket, dwPId, &protocolInfo ) )
  1615. {
  1616. DecodeWSAErrorCodes( WSAGetLastError() );
  1617. return( FALSE );
  1618. }
  1619. if ( !WriteToPipe( hPipeWrite, &protocolInfo, sizeof( WSAPROTOCOL_INFO ),
  1620. &( m_oWriteToPipe ) ) )
  1621. {
  1622. return( FALSE );
  1623. }
  1624. return TRUE;
  1625. }
  1626. bool
  1627. CTelnetService::InformTheClient( SOCKET sSocket, LPSTR pszMsg )
  1628. {
  1629. _chASSERT( pszMsg );
  1630. _chASSERT( sSocket );
  1631. if ( !sSocket || !pszMsg )
  1632. {
  1633. return( FALSE );
  1634. }
  1635. DWORD dwLen = strlen( pszMsg ) + 1;
  1636. OVERLAPPED m_oWriteToSock;
  1637. InitializeOverlappedStruct( &m_oWriteToSock );
  1638. if ( !WriteFile( ( HANDLE ) sSocket, pszMsg, dwLen, &dwLen, &m_oWriteToSock))
  1639. {
  1640. DWORD dwErr;
  1641. if ( ( dwErr = GetLastError( ) ) != ERROR_IO_PENDING )
  1642. {
  1643. if ( dwErr != ERROR_NETNAME_DELETED )
  1644. {
  1645. LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_ERR_WRITESOCKET, dwErr );
  1646. _TRACE( TRACE_DEBUGGING, "Error: WriteFile(InformTheClient) -- 0x%1x", dwErr );
  1647. _TRACE( TRACE_DEBUGGING, "Error writing to socket %d", (DWORD)sSocket);
  1648. }
  1649. return( FALSE );
  1650. }
  1651. }
  1652. TlntSynchronizeOn(m_oWriteToSock.hEvent);
  1653. TELNET_CLOSE_HANDLE( m_oWriteToSock.hEvent );
  1654. return( TRUE );
  1655. }
  1656. //------------------------------------------------------------------------------
  1657. //this is the function which the worker threads execute.
  1658. //------------------------------------------------------------------------------
  1659. DWORD WINAPI
  1660. DoIPCWithClients( LPVOID lpContext )
  1661. {
  1662. _chASSERT( lpContext != NULL );
  1663. if ( !lpContext )
  1664. {
  1665. return( FALSE );
  1666. }
  1667. BOOL bSuccess = FALSE;
  1668. DWORD dwIoSize = 0;
  1669. LPOVERLAPPED lpOverlapped = NULL;
  1670. CClientInfo *pClientInfo = NULL;
  1671. bool bRetVal = TRUE;
  1672. bool bContinue = true;
  1673. CTelnetService *ctService = NULL;
  1674. ctService = ( CTelnetService *)lpContext;
  1675. while ( TRUE )
  1676. {
  1677. bSuccess = GetQueuedCompletionStatus( ctService->m_hCompletionPort,
  1678. &dwIoSize, ( PULONG_PTR ) &pClientInfo, &lpOverlapped, INFINITE );
  1679. if ( bSuccess == 0 )
  1680. {
  1681. if ( lpOverlapped == NULL )
  1682. {
  1683. DWORD dwErr = GetLastError();
  1684. // This could happen during a stop service call....
  1685. _TRACE( TRACE_DEBUGGING, "Error: GetQueuedCompletionStatus -- 0x%1x", dwErr );
  1686. // LogFormattedGetLastError( EVENTLOG_ERROR_TYPE, MSG_FAILGETQ, dwErr );
  1687. // _chASSERT( lpOverlapped != NULL );
  1688. bRetVal = FALSE;
  1689. break;
  1690. }
  1691. else
  1692. {
  1693. DWORD dwErr = GetLastError();
  1694. if ( dwErr == ERROR_MORE_DATA )
  1695. {
  1696. //Some data is read and more is to be read for this Message
  1697. ctService->IssueReadAgain( pClientInfo );
  1698. }
  1699. else
  1700. {
  1701. //When a session exits abruptly, whenever
  1702. //we try to write to it, we fail. As a result, We delete
  1703. //the object. Then, the async read posted on that pipe
  1704. //gets cancelled with the error code ERRO_BROKEN_PIPE.
  1705. //We should not access already deleted object. So....
  1706. if ( dwErr != ERROR_BROKEN_PIPE )
  1707. {
  1708. ctService->StopServicingClient( pClientInfo, (BOOL)TRUE );
  1709. }
  1710. }
  1711. }
  1712. }
  1713. else
  1714. {
  1715. ctService->OnCompletionPacket( pClientInfo, lpOverlapped );
  1716. }
  1717. }
  1718. TELNET_SYNC_CLOSE_HANDLE( g_pTelnetService->m_hCompletionPort );
  1719. return( bRetVal );
  1720. }
  1721. bool
  1722. CTelnetService::StopServicingClient( CClientInfo *pClientInfo, BOOL delete_the_class )
  1723. {
  1724. _chASSERT( pClientInfo );
  1725. bool bRetVal = TRUE;
  1726. DWORD dwErr = 0;
  1727. DWORD dwRetVal = 0,dwAvail = 0, dwLeft = 0;
  1728. CHAR *szBuffer = NULL;
  1729. if (! TlntSynchronizeOn(m_hSyncAllClientObjAccess))
  1730. {
  1731. _TRACE( TRACE_DEBUGGING, "Failed to get access to mutex. Did not "
  1732. " remove the client" );
  1733. return(bRetVal);
  1734. }
  1735. if(!PeekNamedPipe(pClientInfo->hReadingPipe,szBuffer,0,&dwRetVal,&dwAvail,&dwLeft))
  1736. {
  1737. dwRetVal = GetLastError();
  1738. if(dwRetVal == ERROR_INVALID_HANDLE)
  1739. {
  1740. bRetVal = FALSE;
  1741. ReleaseMutex(m_hSyncAllClientObjAccess);
  1742. return(bRetVal);
  1743. }
  1744. }
  1745. if ( !pClientInfo )
  1746. {
  1747. if ( client_list_Count() == 0 )
  1748. {
  1749. bRetVal = FALSE;
  1750. }
  1751. ReleaseMutex(m_hSyncAllClientObjAccess);
  1752. return( bRetVal );
  1753. }
  1754. //Number of active connections decreses by one only if it was given license
  1755. if ( pClientInfo->bLicenseIssued )
  1756. {
  1757. if(m_dwNumOfActiveConnections>0)
  1758. m_dwNumOfActiveConnections--;
  1759. }
  1760. _TRACE( TRACE_DEBUGGING,"removing element from pclientinfo : pid : %d, socket : %d ", pClientInfo->dwPid,(DWORD)pClientInfo->sSocket);
  1761. if ( !client_list_RemoveElem( pClientInfo ) )
  1762. {
  1763. _TRACE( TRACE_DEBUGGING, "Could not delete the client",
  1764. pClientInfo->dwPid );
  1765. }
  1766. if (delete_the_class)
  1767. {
  1768. delete pClientInfo;
  1769. }
  1770. //If there are no more clients to service, exit the thread
  1771. if ( client_list_Count() == 0 )
  1772. {
  1773. bRetVal = FALSE;
  1774. }
  1775. ReleaseMutex( m_hSyncAllClientObjAccess );
  1776. return bRetVal;
  1777. }
  1778. bool
  1779. CTelnetService::OnCompletionPacket( CClientInfo *pClientInfo,
  1780. LPOVERLAPPED lpoObject )
  1781. {
  1782. _chASSERT( lpoObject != NULL );
  1783. _chASSERT( pClientInfo != NULL );
  1784. bool bRetVal = TRUE;
  1785. if ( !lpoObject || !pClientInfo )
  1786. {
  1787. if ( client_list_Count() == 0 )
  1788. {
  1789. bRetVal = FALSE;
  1790. }
  1791. return( bRetVal );
  1792. }
  1793. if ( lpoObject == &m_oReadFromPipe )
  1794. {
  1795. //Asynchronous read from the pipe has finished.
  1796. bRetVal = IPCDataDriver( pClientInfo );
  1797. }
  1798. else if ( lpoObject == &m_oPostedMessage )
  1799. {
  1800. //We should reach here on messages from other threads sent through
  1801. //PostQueuedCompletionStatus
  1802. bRetVal = HandleInProcMessages( TLNTSVR_SHUTDOWN );
  1803. }
  1804. else
  1805. {
  1806. _chASSERT( 0 );
  1807. }
  1808. return bRetVal;
  1809. }
  1810. bool
  1811. CTelnetService::SetNewRegKeyValues( DWORD dwNewTelnetPort,
  1812. DWORD dwNewMaxConnections,
  1813. DWORD dwNewMaxFileSize,
  1814. LPWSTR pszNewLogFile, LPWSTR pszNewIpAddr, DWORD dwLogToFile )
  1815. {
  1816. bool bIPV4 = false;
  1817. bool bIPV6 = false;
  1818. if ( wcscmp( pszNewIpAddr, m_pszIpAddrToListenOn ) || dwNewTelnetPort != m_dwTelnetPort )
  1819. {
  1820. if (m_sFamily[IPV4_FAMILY].sListenSocket && m_sFamily[IPV4_FAMILY].sListenSocket != INVALID_SOCKET)
  1821. {
  1822. _TRACE(TRACE_DEBUGGING,"IPV4 socket closure");
  1823. closesocket( m_sFamily[IPV4_FAMILY].sListenSocket );
  1824. m_sFamily[IPV4_FAMILY].sListenSocket = INVALID_SOCKET;
  1825. bIPV4 = true;
  1826. }
  1827. if (m_sFamily[IPV6_FAMILY].sListenSocket && m_sFamily[IPV6_FAMILY].sListenSocket != INVALID_SOCKET )
  1828. {
  1829. _TRACE(TRACE_DEBUGGING,"IPV6 socket closure");
  1830. closesocket( m_sFamily[IPV6_FAMILY].sListenSocket );
  1831. m_sFamily[IPV6_FAMILY].sListenSocket = INVALID_SOCKET;
  1832. bIPV6 = true;
  1833. }
  1834. delete[] m_pszIpAddrToListenOn;
  1835. m_pszIpAddrToListenOn = pszNewIpAddr;
  1836. m_dwTelnetPort = dwNewTelnetPort;
  1837. if (bIPV4)
  1838. {
  1839. WSAResetEvent( m_sFamily[IPV4_FAMILY].SocketAcceptEvent );
  1840. _TRACE(TRACE_DEBUGGING,"IPV4 socket creation");
  1841. CreateSocket(IPV4_FAMILY);
  1842. }
  1843. if (bIPV6)
  1844. {
  1845. WSAResetEvent( m_sFamily[IPV6_FAMILY].SocketAcceptEvent );
  1846. CreateSocket(IPV6_FAMILY);
  1847. _TRACE(TRACE_DEBUGGING,"IPV6 socket creation");
  1848. }
  1849. }
  1850. if ( dwNewMaxConnections != m_dwMaxConnections )
  1851. {
  1852. /*++
  1853. If the registry value for MaxConnections get modified, we should also
  1854. modify the maximum number of unauthenticated connections allowed.
  1855. --*/
  1856. InterlockedExchange( (PLONG)&m_dwMaxConnections, dwNewMaxConnections );
  1857. InterlockedExchange( (PLONG)&(CQList->m_dwMaxUnauthenticatedConnections), dwNewMaxConnections );
  1858. }
  1859. if ( dwNewMaxFileSize != (DWORD)g_lMaxFileSize )
  1860. {
  1861. InterlockedExchange( &g_lMaxFileSize, dwNewMaxFileSize );
  1862. }
  1863. if ( wcscmp( pszNewLogFile, g_pszLogFile ) != 0 )
  1864. {
  1865. HANDLE *phNewLogFile = NULL;
  1866. HANDLE *phOldLogFile = g_phLogFile;
  1867. phNewLogFile = new HANDLE;
  1868. if ( !phNewLogFile )
  1869. {
  1870. return false;
  1871. }
  1872. InitializeLogFile( pszNewLogFile, phNewLogFile );
  1873. InterlockedExchangePointer( ( PVOID * )&g_phLogFile, phNewLogFile );
  1874. CloseLogFile( &g_pszLogFile, phOldLogFile );
  1875. g_pszLogFile = pszNewLogFile;
  1876. //Don't delete pszNewLogFile
  1877. }
  1878. //Now onwards log to file
  1879. if ( dwLogToFile && !g_fLogToFile )
  1880. {
  1881. g_fLogToFile = true;
  1882. InitializeLogFile( g_pszLogFile, g_phLogFile );
  1883. }
  1884. else
  1885. {
  1886. //Now onwards don't log to file
  1887. if ( !dwLogToFile && g_fLogToFile )
  1888. {
  1889. g_fLogToFile = false;
  1890. TELNET_CLOSE_HANDLE( *g_phLogFile );
  1891. *g_phLogFile = NULL;
  1892. }
  1893. }
  1894. return( TRUE );
  1895. }
  1896. bool
  1897. CTelnetService::HandleInProcMessages( DWORD dwMsg )
  1898. {
  1899. bool bRetVal = TRUE;
  1900. if ( dwMsg == TLNTSVR_SHUTDOWN )
  1901. {
  1902. //Make the thread return
  1903. bRetVal = FALSE;
  1904. }
  1905. return bRetVal;
  1906. }
  1907. //Each IPC packet is to be decoded in the following manner:
  1908. //UCHAR Message : indicating type of message
  1909. //DWORD Size : size of the following message if any
  1910. //UCHAR *Data : data if any for the given message
  1911. //When a message indicates that it is may have variable size, The first element
  1912. //Data points is of a DWORD indicating size and then the data.
  1913. //This is not true for the initial socket handover where only protocol structure
  1914. //is sent.
  1915. bool
  1916. CTelnetService::IPCDataDriver( CClientInfo *pClientInfo )
  1917. {
  1918. _chASSERT( pClientInfo );
  1919. bool bRetVal = true;
  1920. if ( !pClientInfo )
  1921. {
  1922. if ( client_list_Count() == 0 )
  1923. {
  1924. bRetVal = false;
  1925. }
  1926. return bRetVal;
  1927. }
  1928. UCHAR *pBuff = NULL;
  1929. //Don't do a delete on pBuff by mistake
  1930. pBuff = pClientInfo->m_ReadFromPipeBuffer;
  1931. bool bStopService = false;
  1932. bool bIsLicenseIssued = false;
  1933. DWORD dwPid=0;
  1934. switch ( *pBuff++ )
  1935. {
  1936. case RESET_IDLE_TIME:
  1937. pClientInfo->m_dwIdleTime = 0;
  1938. break;
  1939. case UPDATE_IDLE_TIME:
  1940. pClientInfo->m_dwIdleTime += MAX_POLL_INTERVAL;
  1941. break;
  1942. case SESSION_EXIT:
  1943. dwPid = (DWORD)pClientInfo->dwPid;
  1944. bRetVal = ExitTheSession( pClientInfo );
  1945. _TRACE(TRACE_DEBUGGING,"Deleting session pid : %d",dwPid);
  1946. CQList->FreeEntry(dwPid);
  1947. goto FinishTheThread;
  1948. case AUDIT_CLIENT :
  1949. //The data is expected exactly in the form used
  1950. //to be written in the file
  1951. pBuff += sizeof( DWORD ); //Move past message size
  1952. if ( *g_phLogFile )
  1953. {
  1954. WriteAuditedMsgsToFile( ( CHAR * )pBuff );
  1955. }
  1956. //delete the message. Such a big amt of memory
  1957. //is no more needed
  1958. delete[] (pClientInfo->m_ReadFromPipeBuffer);
  1959. pClientInfo->m_ReadFromPipeBuffer = new UCHAR[
  1960. IPC_HEADER_SIZE ];
  1961. if (!pClientInfo->m_ReadFromPipeBuffer )
  1962. {
  1963. bStopService = true;
  1964. }
  1965. pClientInfo->m_dwRequestedSize = IPC_HEADER_SIZE;
  1966. break;
  1967. case SESSION_DETAILS:
  1968. HandleSessionDetailsMessage( pClientInfo );
  1969. _TRACE(TRACE_DEBUGGING,L"In session_details");
  1970. //delete the message. Such a big amt of memory
  1971. //is no more needed
  1972. if (pClientInfo->m_ReadFromPipeBuffer )
  1973. {
  1974. _TRACE(TRACE_DEBUGGING,L"deleting ReadFromPipeBuffer");
  1975. delete[] ( pClientInfo->m_ReadFromPipeBuffer );
  1976. pClientInfo->m_ReadFromPipeBuffer = NULL;
  1977. }
  1978. pClientInfo->m_ReadFromPipeBuffer =
  1979. new UCHAR[ IPC_HEADER_SIZE ];
  1980. if ( !pClientInfo->m_ReadFromPipeBuffer )
  1981. {
  1982. bStopService = true;
  1983. pClientInfo->m_dwRequestedSize = 0;
  1984. _TRACE(TRACE_DEBUGGING,L"new failed for ReadFromPipeBuffer");
  1985. goto ExitOnErrorInDetails;
  1986. }
  1987. else
  1988. {
  1989. pClientInfo->m_dwRequestedSize = IPC_HEADER_SIZE;
  1990. if ( !CheckLicense( &bIsLicenseIssued, pClientInfo ) )
  1991. {
  1992. bStopService = true;
  1993. _TRACE(TRACE_DEBUGGING,L"checklicense failed");
  1994. goto ExitOnErrorInDetails;
  1995. }
  1996. if ( !IssueLicense( bIsLicenseIssued, pClientInfo ) )
  1997. {
  1998. bStopService = true;
  1999. _TRACE(TRACE_DEBUGGING,L"issue license failed");
  2000. goto ExitOnErrorInDetails;
  2001. }
  2002. }
  2003. //Close the session soc handle
  2004. ExitOnErrorInDetails:
  2005. pClientInfo->CloseClientSocket() ;
  2006. break;
  2007. default:
  2008. _TRACE( TRACE_DEBUGGING, "Unknown IPC message:%uc",
  2009. pClientInfo->m_ReadFromPipeBuffer[0] );
  2010. }
  2011. //Reset where to read -- Begining of the buffer
  2012. pClientInfo->m_dwPosition = 0;
  2013. //Issue a read call again
  2014. if ( bStopService || !IssueReadFromPipe( pClientInfo ) )
  2015. {
  2016. bRetVal = StopServicingClient( pClientInfo, (BOOL)TRUE );
  2017. }
  2018. FinishTheThread:
  2019. return( bRetVal );
  2020. }
  2021. void
  2022. CTelnetService::HandleSessionDetailsMessage( CClientInfo *pClientInfo )
  2023. {
  2024. UCHAR *pBuff = NULL;
  2025. if (!pClientInfo->m_ReadFromPipeBuffer)
  2026. {
  2027. return;
  2028. }
  2029. //Don't do a delete on pBuff by mistake
  2030. pBuff = pClientInfo->m_ReadFromPipeBuffer;
  2031. pBuff++; // Move past Message type
  2032. pBuff += sizeof( DWORD ); //Move past message size
  2033. DWORD dwStrLen = 0;
  2034. //Domain
  2035. dwStrLen = strlen( ( LPCSTR ) pBuff ) + 1;
  2036. pClientInfo->szDomain = new CHAR[ dwStrLen ];
  2037. if ( !pClientInfo->szDomain )
  2038. {
  2039. return;
  2040. }
  2041. memcpy( pClientInfo->szDomain, pBuff, dwStrLen ); // No BO in this Baskar
  2042. pBuff += dwStrLen;
  2043. //Username
  2044. dwStrLen = strlen( ( LPCSTR ) pBuff ) + 1;
  2045. pClientInfo->szUserName = new CHAR[ dwStrLen ];
  2046. if ( !pClientInfo->szUserName )
  2047. {
  2048. return;
  2049. }
  2050. memcpy( pClientInfo->szUserName, pBuff, dwStrLen ); // No BO in this Baskar
  2051. pBuff += dwStrLen;
  2052. //Remote machine
  2053. dwStrLen = strlen( ( LPCSTR ) pBuff ) + 1;
  2054. pClientInfo->szRemoteMachine = new CHAR[ dwStrLen ];
  2055. if ( !pClientInfo->szRemoteMachine )
  2056. {
  2057. return;
  2058. }
  2059. memcpy( pClientInfo->szRemoteMachine, pBuff, dwStrLen ); // No BO in this Baskar
  2060. pBuff += dwStrLen;
  2061. //Logon identifier
  2062. pClientInfo->pAuthId = new LUID;
  2063. if ( !pClientInfo->pAuthId )
  2064. {
  2065. return;
  2066. }
  2067. memcpy( pClientInfo->pAuthId, pBuff, sizeof( LUID ) ); // No BO in this Baskar
  2068. pClientInfo->lpLogonTime = new SYSTEMTIME;
  2069. if ( !pClientInfo->lpLogonTime )
  2070. {
  2071. return;
  2072. }
  2073. GetSystemTime( pClientInfo->lpLogonTime );
  2074. }
  2075. bool
  2076. CTelnetService::ExitTheSession( CClientInfo *pClientInfo )
  2077. {
  2078. bool bRetVal = TRUE;
  2079. _TRACE( TRACE_DEBUGGING, "ExitTheSession -- pid : %d, socket :%d",
  2080. pClientInfo->dwPid,( DWORD ) pClientInfo->sSocket );
  2081. bRetVal = StopServicingClient( pClientInfo, (BOOL)TRUE );
  2082. return bRetVal;
  2083. }