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.

386 lines
13 KiB

  1. // RDSHost.cpp : Implementation of WinMain
  2. // Note: Proxy/Stub Information
  3. // To build a separate proxy/stub DLL,
  4. // run nmake -f RDSHostps.mk in the project directory.
  5. #include "stdafx.h"
  6. #ifdef TRC_FILE
  7. #undef TRC_FILE
  8. #endif
  9. #define TRC_FILE "_rdshost"
  10. #include "resource.h"
  11. #include <initguid.h>
  12. #include "RDSHost.h"
  13. #include "RDSHost_i.c"
  14. #include "RemoteDesktopServerHost.h"
  15. extern CRemoteDesktopServerHost* g_pRemoteDesktopServerHostObj;
  16. const DWORD dwTimeOut = 5000; // time for EXE to be idle before shutting down
  17. const DWORD dwPause = 1000; // time to wait for threads to finish up
  18. // Passed to CreateThread to monitor the shutdown event
  19. static DWORD WINAPI MonitorProc(void* pv)
  20. {
  21. CExeModule* p = (CExeModule*)pv;
  22. p->MonitorShutdown();
  23. return 0;
  24. }
  25. LONG CExeModule::Lock()
  26. {
  27. DC_BEGIN_FN("CExeModule::Lock");
  28. LONG l = CComModule::Lock();
  29. TRC_NRM((TB, L"Lock count: %ld", l));
  30. DC_END_FN();
  31. return l;
  32. }
  33. LONG CExeModule::Unlock()
  34. {
  35. DC_BEGIN_FN("CExeModule::Unlock");
  36. LONG l = CComModule::Unlock();
  37. if (l == 0)
  38. {
  39. bActivity = true;
  40. SetEvent(hEventShutdown); // tell monitor that we transitioned to zero
  41. }
  42. TRC_NRM((TB, L"Lock count: %ld", l));
  43. DC_END_FN();
  44. return l;
  45. }
  46. //Monitors the shutdown event
  47. void CExeModule::MonitorShutdown()
  48. {
  49. DWORD dwGPWait=0;
  50. while (1)
  51. {
  52. dwGPWait = WaitForRAGPDisableNotification( hEventShutdown );
  53. if( dwGPWait != ERROR_SHUTDOWN_IN_PROGRESS ) {
  54. // either error occurred setting notification or
  55. // RA has been disabled via policy, post WM_QUIT to
  56. // terminate main thread.
  57. break;
  58. }
  59. //WaitForSingleObject(hEventShutdown, INFINITE);
  60. DWORD dwWait;
  61. do
  62. {
  63. bActivity = false;
  64. dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
  65. } while (dwWait == WAIT_OBJECT_0);
  66. // timed out
  67. if (!bActivity && m_nLockCnt == 0) // if no activity let's really bail
  68. {
  69. #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
  70. CoSuspendClassObjects();
  71. if (!bActivity && m_nLockCnt == 0)
  72. #endif
  73. break;
  74. }
  75. }
  76. CloseHandle(hEventShutdown);
  77. // post WM_RADISABLED message to main thread if shutdown is due to RA disable.
  78. PostThreadMessage(dwThreadID, (dwGPWait == ERROR_SUCCESS) ? WM_RADISABLED : WM_QUIT, 0, 0);
  79. }
  80. bool CExeModule::StartMonitor()
  81. {
  82. hEventShutdown = CreateEvent(NULL, false, false, NULL);
  83. if (hEventShutdown == NULL)
  84. return false;
  85. DWORD dwThreadID;
  86. HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);
  87. return (h != NULL);
  88. }
  89. CExeModule _Module;
  90. BEGIN_OBJECT_MAP(ObjectMap)
  91. OBJECT_ENTRY(CLSID_SAFRemoteDesktopServerHost, CRemoteDesktopServerHost)
  92. END_OBJECT_MAP()
  93. LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
  94. {
  95. while (p1 != NULL && *p1 != NULL)
  96. {
  97. LPCTSTR p = p2;
  98. while (p != NULL && *p != NULL)
  99. {
  100. if (*p1 == *p)
  101. return CharNext(p1);
  102. p = CharNext(p);
  103. }
  104. p1 = CharNext(p1);
  105. }
  106. return NULL;
  107. }
  108. extern CRemoteDesktopServerHost* g_pRemoteDesktopServerHostObj;
  109. /////////////////////////////////////////////////////////////////////////////
  110. //
  111. extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
  112. HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
  113. {
  114. lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
  115. DWORD dwStatus = ERROR_SUCCESS;
  116. PSID pEveryoneSID = NULL;
  117. LPWSTR pszEveryoneAccName = NULL;
  118. DWORD cbEveryoneAccName = 0;
  119. LPWSTR pszEveryoneDomainName = NULL;
  120. DWORD cbEveryoneDomainName = 0;
  121. SID_NAME_USE SidType;
  122. BOOL bSuccess;
  123. SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
  124. //
  125. // Create a well-known SID for the Everyone group, this code is just
  126. // to keep app. verifier happy.
  127. //
  128. if(FALSE == AllocateAndInitializeSid( &SIDAuthWorld, 1,
  129. SECURITY_WORLD_RID,
  130. 0, 0, 0, 0, 0, 0, 0,
  131. &pEveryoneSID) ) {
  132. // what can we do here? this is not a critical error, just trying to
  133. // get AppVerifier happen
  134. dwStatus = GetLastError();
  135. _ASSERTE(dwStatus == ERROR_SUCCESS);
  136. }
  137. #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
  138. HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  139. #else
  140. HRESULT hRes = CoInitialize(NULL);
  141. #endif
  142. _ASSERTE(SUCCEEDED(hRes));
  143. //
  144. // This makes us accessible by anyone from user-mode. This is required from
  145. // a security perspective because our interfaces are passed from SYSTEM context
  146. // to USER context, by a "trusted" creator.
  147. //
  148. CSecurityDescriptor sd;
  149. sd.InitializeFromThreadToken();
  150. //
  151. // If we failed in getting Everyone SID, just use default COM security which is everyone access
  152. // this code is just to keep app. verifier happy
  153. //
  154. if(ERROR_SUCCESS == dwStatus ) {
  155. //
  156. // Retrieve System account name, might not be necessary since this
  157. // pre-defined account shouldn't be localizable.
  158. //
  159. bSuccess = LookupAccountSid(
  160. NULL,
  161. pEveryoneSID,
  162. pszEveryoneAccName,
  163. &cbEveryoneAccName,
  164. pszEveryoneDomainName,
  165. &cbEveryoneDomainName,
  166. &SidType
  167. );
  168. if( TRUE == bSuccess ||
  169. ERROR_INSUFFICIENT_BUFFER == GetLastError() ) {
  170. pszEveryoneAccName = (LPWSTR) LocalAlloc( LPTR, (cbEveryoneAccName + 1) * sizeof(WCHAR) );
  171. pszEveryoneDomainName = (LPWSTR) LocalAlloc( LPTR, (cbEveryoneDomainName + 1) * sizeof(WCHAR) );
  172. if( NULL != pszEveryoneAccName && NULL != pszEveryoneDomainName ) {
  173. bSuccess = LookupAccountSid(
  174. NULL,
  175. pEveryoneSID,
  176. pszEveryoneAccName,
  177. &cbEveryoneAccName,
  178. pszEveryoneDomainName,
  179. &cbEveryoneDomainName,
  180. &SidType
  181. );
  182. if( TRUE == bSuccess ) {
  183. hRes = sd.Allow( pszEveryoneAccName, COM_RIGHTS_EXECUTE );
  184. // ASSERT on check build just for tracking purpose, we can still continue
  185. // since our default is everyone has access to our com object, code
  186. // here is just to keep app. verifier happy.
  187. _ASSERTE(SUCCEEDED(hRes));
  188. }
  189. }
  190. }
  191. }
  192. HRESULT testHR = CoInitializeSecurity(sd, -1, NULL, NULL,
  193. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY,
  194. NULL, EOAC_NONE, NULL);
  195. _ASSERTE(SUCCEEDED(testHR));
  196. _Module.Init(ObjectMap, hInstance, &LIBID_RDSSERVERHOSTLib);
  197. _Module.dwThreadID = GetCurrentThreadId();
  198. TCHAR szTokens[] = _T("-/");
  199. int nRet = 0;
  200. BOOL bRun = TRUE;
  201. LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
  202. while (lpszToken != NULL)
  203. {
  204. if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
  205. {
  206. _Module.UpdateRegistryFromResource(IDR_RDSHost, FALSE);
  207. nRet = _Module.UnregisterServer(TRUE);
  208. bRun = FALSE;
  209. break;
  210. }
  211. if (lstrcmpi(lpszToken, _T("RegServer"))==0)
  212. {
  213. _Module.UpdateRegistryFromResource(IDR_RDSHost, TRUE);
  214. nRet = _Module.RegisterServer(TRUE);
  215. bRun = FALSE;
  216. break;
  217. }
  218. lpszToken = FindOneOf(lpszToken, szTokens);
  219. }
  220. if (bRun)
  221. {
  222. WSADATA wsaData;
  223. //
  224. // ignore WinSock startup error, failure in starting Winsock does not
  225. // damage our function, only thing will failed is gethostbyname()
  226. // which is use in callback, however, connection parameter contain
  227. // all IP address except last one is the machine name.
  228. //
  229. WSAStartup(0x0101, &wsaData);
  230. _Module.StartMonitor();
  231. #if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
  232. hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER,
  233. REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
  234. _ASSERTE(SUCCEEDED(hRes));
  235. hRes = CoResumeClassObjects();
  236. #else
  237. hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER,
  238. REGCLS_MULTIPLEUSE);
  239. #endif
  240. _ASSERTE(SUCCEEDED(hRes));
  241. MSG msg;
  242. while (GetMessage(&msg, 0, 0, 0)) {
  243. if( msg.message == WM_TICKETEXPIRED ) {
  244. if( WaitForSingleObject(_Module.hEventShutdown, 0) == WAIT_OBJECT_0 ) {
  245. // shutdown event has been signal, don't need to do anything
  246. continue;
  247. }
  248. else {
  249. CRemoteDesktopServerHost *pSrvHostObj;
  250. pSrvHostObj = (CRemoteDesktopServerHost *)msg.lParam;
  251. if( pSrvHostObj != NULL ) {
  252. pSrvHostObj->ExpirateTicketAndSetupNextExpiration();
  253. }
  254. }
  255. }
  256. else if( WM_RADISABLED == msg.message ) {
  257. if( g_pRemoteDesktopServerHostObj ) {
  258. HANDLE hDummy;
  259. DWORD dummy;
  260. hDummy = CreateEvent( NULL, TRUE, FALSE, NULL );
  261. //
  262. // We invoke seperate routine in CRemoteDesktopServerHost object
  263. // to disconnect all existing RA conenction, we want to do this here
  264. // instead of ~CRemoteDesktopServerHost() during RevokeClassObjects() so
  265. // we can notify client of RA disconnect.
  266. //
  267. g_pRemoteDesktopServerHostObj->RemoteDesktopDisabled();
  268. if( hDummy ) {
  269. //
  270. // A wait is necessary here since RDSHOST is apartment
  271. // threaded. Disconnect() call will terminate namedpipe connection
  272. // and ChannelMgr will try to Fire_ClientDisconnected(), however,
  273. // this Fire_XXX will not be processed because main thread still
  274. // executing this function, also, it takes time for ChannelMgr to
  275. // shutdown so if we RDSHOST shutdown too quickly, client will
  276. // never receive disconnect notification.
  277. //
  278. CoWaitForMultipleHandles(
  279. COWAIT_ALERTABLE,
  280. 5*1000,
  281. 1,
  282. &hDummy,
  283. &dummy
  284. );
  285. CloseHandle( hDummy );
  286. }
  287. g_pRemoteDesktopServerHostObj = NULL;
  288. break;
  289. }
  290. }
  291. else {
  292. DispatchMessage(&msg);
  293. }
  294. }
  295. _Module.RevokeClassObjects();
  296. Sleep(dwPause); //wait for any threads to finish
  297. WSACleanup();
  298. }
  299. _Module.Term();
  300. CoUninitialize();
  301. #if DBG
  302. //
  303. // ATL problem.
  304. // App. verify break on atlcom.h line 932, free(m_pDACL), this is because m_pDACL is allocated
  305. // using new in CSecurityDescriptor::AddAccessAllowedACEToACL(); however, in check build, this is
  306. // redirected to our RemoteDesktopAllocateMem() and can't be free by free(), trying to
  307. // #undef DEBUGMEM to not use our new operator does not work so delete it manually
  308. //
  309. if( sd.m_pDACL ) {
  310. // LAB01 has new ATL but other lab does not have it,
  311. // take the one time memory leak for now.
  312. sd.m_pDACL = NULL;
  313. }
  314. #endif
  315. if( pEveryoneSID ) {
  316. FreeSid( pEveryoneSID );
  317. }
  318. if( pszEveryoneAccName ) {
  319. LocalFree( pszEveryoneAccName );
  320. }
  321. if( pszEveryoneDomainName ) {
  322. LocalFree( pszEveryoneDomainName );
  323. }
  324. return nRet;
  325. }