Source code of Windows XP (NT5)
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.

390 lines
9.6 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997 - 1999
  5. //
  6. // File: REMRRAS.CPP
  7. //
  8. //----------------------------------------------------------------------------
  9. // Note: Proxy/Stub Information
  10. // To build a separate proxy/stub DLL,
  11. // run nmake -f remrrasps.mk in the project directory.
  12. #include "stdafx.h"
  13. #include <iaccess.h> // IAccessControl
  14. #include "resource.h"
  15. #include "initguid.h"
  16. #include "remras.h"
  17. #include "ncutil.h"
  18. #include "atlapp.h"
  19. #include "atltmp.h"
  20. //nclude "remrras_i.c"
  21. #include "RemCfg.h"
  22. #include <statreg.h>
  23. #include <statreg.cpp>
  24. #include <atlimpl.cpp>
  25. HRESULT CommitIPInfo();
  26. void RestartRouter();
  27. DWORD WaitForServiceToStop(SC_HANDLE hService);
  28. LONG CExeModule::Unlock()
  29. {
  30. LONG l = CComModule::Unlock();
  31. if (l == 0)
  32. {
  33. #if _WIN32_WINNT >= 0x0400
  34. if (CoSuspendClassObjects() == S_OK)
  35. PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
  36. #else
  37. PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
  38. #endif
  39. }
  40. return l;
  41. }
  42. CExeModule _Module;
  43. BEGIN_OBJECT_MAP(ObjectMap)
  44. OBJECT_ENTRY(CLSID_RemoteRouterConfig, CRemCfg)
  45. END_OBJECT_MAP()
  46. LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
  47. {
  48. while (*p1 != NULL)
  49. {
  50. LPCTSTR p = p2;
  51. while (*p != NULL)
  52. {
  53. if (*p1 == *p++)
  54. return p1+1;
  55. }
  56. p1++;
  57. }
  58. return NULL;
  59. }
  60. DWORD g_dwTraceHandle = 0;
  61. extern BOOL s_fWriteIPConfig;
  62. extern BOOL s_fRestartRouter;
  63. HRESULT GrantAdministratorsGroupAccess()
  64. {
  65. TCHAR szBuffer[1024];
  66. IAccessControl* pAccessControl = NULL;
  67. HRESULT hr = CoCreateInstance(CLSID_DCOMAccessControl, NULL, CLSCTX_INPROC_SERVER,
  68. IID_IAccessControl, (void**)&pAccessControl);
  69. if(FAILED(hr))
  70. goto Error;
  71. // Setup the property list. We use the NULL property because we are
  72. // trying to adjust the security of the object itself
  73. ACTRL_ACCESSW access;
  74. ACTRL_PROPERTY_ENTRYW propEntry;
  75. access.cEntries = 1;
  76. access.pPropertyAccessList = &propEntry;
  77. ACTRL_ACCESS_ENTRY_LISTW entryList;
  78. propEntry.lpProperty = NULL;
  79. propEntry.pAccessEntryList = &entryList;
  80. propEntry.fListFlags = 0;
  81. // Setup the access control list for the default property
  82. ACTRL_ACCESS_ENTRYW entry;
  83. entryList.cEntries = 1;
  84. entryList.pAccessList = &entry;
  85. // Setup the access control entry
  86. entry.fAccessFlags = ACTRL_ACCESS_ALLOWED;
  87. entry.Access = COM_RIGHTS_EXECUTE;
  88. entry.ProvSpecificAccess = 0;
  89. entry.Inheritance = NO_INHERITANCE;
  90. entry.lpInheritProperty = NULL;
  91. // NT requires the system account to have access (for launching)
  92. entry.Trustee.pMultipleTrustee = NULL;
  93. entry.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  94. entry.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
  95. entry.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  96. ::LoadString(NULL, IDS_NT_AUTHORITY_ADMINISTRATORS, szBuffer,
  97. 256);
  98. entry.Trustee.ptstrName = szBuffer;
  99. hr = pAccessControl->GrantAccessRights(&access);
  100. if(FAILED(hr))
  101. {
  102. #ifdef __PRIVATE_DEBUG
  103. TCHAR msg[1024];
  104. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, msg, 1024, 0);
  105. MessageBox(NULL,msg, L"Error", MB_OK);
  106. #endif
  107. goto Error;
  108. }
  109. hr = CoInitializeSecurity(pAccessControl, -1, NULL, NULL,
  110. RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IDENTIFY,
  111. NULL, EOAC_ACCESS_CONTROL, NULL);
  112. Error:
  113. if(pAccessControl)
  114. pAccessControl->Release();
  115. return hr;
  116. }
  117. /////////////////////////////////////////////////////////////////////////////
  118. //
  119. extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
  120. HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
  121. {
  122. lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
  123. HRESULT hRes = CoInitialize(NULL);
  124. hRes = GrantAdministratorsGroupAccess();
  125. // If you are running on NT 4.0 or higher you can use the following call
  126. // instead to make the EXE free threaded.
  127. // This means that calls come in on a random RPC thread
  128. // HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  129. _ASSERTE(SUCCEEDED(hRes));
  130. _Module.Init(ObjectMap, hInstance);
  131. _Module.dwThreadID = GetCurrentThreadId();
  132. TCHAR szTokens[] = _T("-/");
  133. int nRet = 0;
  134. BOOL bRun = TRUE;
  135. s_fWriteIPConfig = FALSE;
  136. s_fRestartRouter = FALSE;
  137. LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);
  138. while (lpszToken != NULL)
  139. {
  140. if (lstrcmpi(lpszToken, _T("UnregServer"))==0)
  141. {
  142. _Module.UpdateRegistryFromResource(IDR_Remrras, FALSE);
  143. nRet = _Module.UnregisterServer();
  144. bRun = FALSE;
  145. break;
  146. }
  147. if (lstrcmpi(lpszToken, _T("RegServer"))==0)
  148. {
  149. _Module.UpdateRegistryFromResource(IDR_Remrras, TRUE);
  150. nRet = _Module.RegisterServer(TRUE);
  151. bRun = FALSE;
  152. break;
  153. }
  154. if (lstrcmpi(lpszToken, _T("Restart")) == 0)
  155. {
  156. RestartRouter();
  157. bRun = FALSE;
  158. nRet = 0;
  159. break;
  160. }
  161. lpszToken = FindOneOf(lpszToken, szTokens);
  162. }
  163. if (bRun)
  164. {
  165. g_dwTraceHandle = TraceRegister(_T("remrras"));
  166. TraceSz("Entering remrras.exe");
  167. hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER,
  168. REGCLS_MULTIPLEUSE);
  169. _ASSERTE(SUCCEEDED(hRes));
  170. MSG msg;
  171. while (GetMessage(&msg, 0, 0, 0))
  172. DispatchMessage(&msg);
  173. _Module.RevokeClassObjects();
  174. // At this point, check the global flag to see if there is work
  175. // to be done.
  176. if (s_fWriteIPConfig)
  177. {
  178. TraceSz("The IP Configuration is being changed.");
  179. CoUninitialize();
  180. CoInitialize(NULL);
  181. CommitIPInfo();
  182. }
  183. if (s_fRestartRouter)
  184. {
  185. // There's no point in doing any kind of error code
  186. RestartRouter();
  187. }
  188. TraceSz("Exiting remrras.exe\n");
  189. TraceDeregister(g_dwTraceHandle);
  190. }
  191. CoUninitialize();
  192. return nRet;
  193. }
  194. static DWORD s_dwTickBegin = 0;
  195. static DWORD s_dwLastCheckPoint = -1;
  196. static DWORD s_dwWaitPeriod = 18000;
  197. void RestartRouter()
  198. {
  199. DWORD dwErr = ERROR_SUCCESS;
  200. SC_HANDLE hScManager = 0;
  201. SC_HANDLE hService = 0;
  202. //
  203. // Open the SCManager so that we can try to stop the service
  204. //
  205. hScManager = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  206. if (hScManager == NULL)
  207. dwErr = ::GetLastError();
  208. if (hScManager && (dwErr == ERROR_SUCCESS))
  209. {
  210. hService = ::OpenService(hScManager,
  211. _T("RemoteAccess"),
  212. SERVICE_STOP | SERVICE_START |
  213. SERVICE_QUERY_STATUS);
  214. if (hService == NULL)
  215. dwErr = ::GetLastError();
  216. }
  217. if (hService && (dwErr == ERROR_SUCCESS))
  218. {
  219. SERVICE_STATUS serviceStatus;
  220. // Stop the RemoteAccess Service
  221. if (::ControlService(hService, SERVICE_CONTROL_STOP,
  222. &serviceStatus))
  223. {
  224. // We are now stopping the service, we need to wait
  225. // the proper amount of time
  226. s_dwTickBegin = GetTickCount();
  227. // get the wait period
  228. ::ZeroMemory(&serviceStatus, sizeof(serviceStatus));
  229. if (QueryServiceStatus(hService, &serviceStatus))
  230. s_dwWaitPeriod = serviceStatus.dwWaitHint;
  231. dwErr = WaitForServiceToStop(hService);
  232. }
  233. else
  234. {
  235. dwErr = ::GetLastError();
  236. // Is the service already stopped?
  237. if (dwErr == ERROR_SERVICE_NOT_ACTIVE)
  238. {
  239. dwErr = ERROR_SUCCESS;
  240. }
  241. }
  242. }
  243. if (hService && (dwErr == ERROR_SUCCESS))
  244. {
  245. SERVICE_STATUS serviceStatus;
  246. // Start the RemoteAccess Service
  247. ::StartService(hService, NULL, NULL);
  248. }
  249. if (hService)
  250. ::CloseServiceHandle(hService);
  251. if (hScManager)
  252. ::CloseServiceHandle(hScManager);
  253. }
  254. BOOL CheckForError(SERVICE_STATUS * pServiceStats)
  255. {
  256. BOOL fError = FALSE;
  257. DWORD dwTickCurrent = GetTickCount();
  258. if (pServiceStats->dwCheckPoint == 0)
  259. {
  260. // the service is in some state, not pending anything.
  261. // before calling this function the code should check to see if
  262. // the service is in the correct state. This means it is in
  263. // some unexpected state.
  264. fError = TRUE;
  265. }
  266. else
  267. if ((dwTickCurrent - s_dwTickBegin) > s_dwWaitPeriod)
  268. {
  269. // ok to check the dwCheckPoint field to see if
  270. // everything is going ok
  271. if (s_dwLastCheckPoint == -1)
  272. {
  273. s_dwLastCheckPoint = pServiceStats->dwCheckPoint;
  274. }
  275. else
  276. {
  277. if (s_dwLastCheckPoint >= pServiceStats->dwCheckPoint)
  278. {
  279. fError = TRUE;
  280. }
  281. }
  282. s_dwLastCheckPoint = pServiceStats->dwCheckPoint;
  283. s_dwTickBegin = dwTickCurrent;
  284. s_dwWaitPeriod = pServiceStats->dwWaitHint;
  285. }
  286. return fError;
  287. }
  288. DWORD WaitForServiceToStop(SC_HANDLE hService)
  289. {
  290. SERVICE_STATUS serviceStatus;
  291. DWORD dwErr = ERROR_SUCCESS;
  292. do
  293. {
  294. ::ZeroMemory(&serviceStatus, sizeof(serviceStatus));
  295. if (!QueryServiceStatus(hService, &serviceStatus))
  296. {
  297. dwErr = ::GetLastError();
  298. break;
  299. }
  300. // If the dwCheckpoint value is 0, then there is no start/stop/pause
  301. // or continue action pending (in which case we can exit no matter
  302. // what happened).
  303. if (serviceStatus.dwCurrentState == SERVICE_STOPPED)
  304. break;
  305. if (CheckForError(&serviceStatus))
  306. {
  307. // Something failed. Report an error.
  308. if (serviceStatus.dwWin32ExitCode)
  309. dwErr = serviceStatus.dwWin32ExitCode;
  310. else
  311. dwErr = ERROR_SERVICE_REQUEST_TIMEOUT;
  312. break;
  313. }
  314. // Now we sleep
  315. Sleep(5000);
  316. }
  317. while (TRUE);
  318. return dwErr;
  319. }