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.

572 lines
14 KiB

  1. #include <windows.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <tchar.h>
  5. #include "service.h"
  6. #include "network.h"
  7. #include "idw_dbg.h"
  8. #include "idwlog.h"
  9. #include "files.h"
  10. // Global variables
  11. HANDLE terminateEvent = NULL;
  12. HANDLE g_hThread = 0;
  13. SERVICE_STATUS ssStatus;
  14. SERVICE_STATUS_HANDLE serviceStatusHandle;
  15. BOOL bPause = FALSE;
  16. BOOL bRunning = FALSE;
  17. BOOL bKeepThreadAlive = TRUE;
  18. /*******************************************************
  19. #if _MSC_FULL_VER >= 13008827
  20. #pragma warning(push)
  21. #pragma warning(disable:4715)
  22. // Not all control paths return (due to infinite loop)
  23. #endif
  24. *******************************************************/
  25. /******************************
  26. #if _MSC_FULL_VER >= 13008827
  27. #pragma warning(pop)
  28. #endif
  29. ******************************/
  30. DWORD
  31. ServiceThread(LPDWORD param)
  32. {
  33. MACHINE_DETAILS md;
  34. BOOL b;
  35. INSTALL_DATA id2;
  36. DWORD dwError = TRUE;
  37. __try{
  38. ZeroMemory((LPINSTALL_DATA) &id2, sizeof(id2));
  39. // Set the sequence of which stage we are in.
  40. g_InstallData.iStageSequence = 2;
  41. OpenIdwlogDebugFile(WRITE_NORMAL_DBG);
  42. Idwlog(TEXT("\nSTARTED -- [IDWLOG: Stage2 - Service]\n"));
  43. IdwlogClient( &g_InstallData, &md );
  44. // The below will overwrite fields that are filled in as wrong
  45. // from the above call to IdwlogClient. Such as the username and
  46. // userdomain.
  47. g_InstallData.bFindBLDFile = TRUE;
  48. Idwlog(TEXT("Reading the username and userdomain from the cookie\n"));
  49. b = ReadIdwlogCookie (&g_InstallData);
  50. if (TRUE == b &&
  51. TRUE == g_InstallData.bFindBLDFile) {
  52. Idwlog(TEXT("Server from cookie is %s.\n"), g_InstallData.szIdwlogServer);
  53. // If this returns fail we leave the link
  54. // and the file intact upon next boot.
  55. if (FALSE == ServerWriteMaximum (&g_InstallData, &md)) {
  56. dwError = FALSE;
  57. __leave;
  58. }
  59. } else {
  60. //If we are here we have read the cookie and
  61. // found that NO_BUILD_DATA was in the cookie.
  62. // Which means part one didn't find a bld file.
  63. // and the cookie is empty.
  64. // What we do now is make an assumption. This being
  65. // That the system build is the current build that
  66. // we either couldn't get to begin with or that
  67. // a CD BOOT happened. Both cases we distinguish.
  68. // We get the current system information and then
  69. // send it as the installing build.
  70. // of course we blank out the data for everything else.
  71. GetCurrentSystemBuildInfo(&id2);
  72. g_InstallData.dwSystemBuild = 0;
  73. g_InstallData.dwSystemBuildDelta = 0;
  74. _tcscpy(g_InstallData.szInstallingBuildSourceLocation, TEXT("No_Build_Lab_Information"));
  75. g_InstallData.dwInstallingBuild = id2.dwSystemBuild ;
  76. g_InstallData.dwInstallingBuildDelta = id2.dwSystemBuildDelta;
  77. _tcscpy(g_InstallData.szInstallingBuildSourceLocation, id2.szSystemBuildSourceLocation);
  78. g_InstallData.bFindBLDFile = g_InstallData.bFindBLDFile;
  79. if (FALSE == g_InstallData.bFindBLDFile) {
  80. g_InstallData.bCDBootInstall = FALSE;
  81. // If there was no build file found.
  82. Idwlog(TEXT("There was no build file in part 1 logging as such.\n"));
  83. //Remove the CookieFile.
  84. // DeleteCookieFile();
  85. dwError = FALSE;
  86. __leave;
  87. } else {
  88. // We will probe the machine to get a build number
  89. // then we will send a minimal server file over to the server.
  90. // This will have a build number machine id name of computer
  91. // on the file name. But will have a delta inside.
  92. g_InstallData.bCDBootInstall = TRUE;
  93. Idwlog(TEXT("This is a CD Boot Install logging as such.\n"));
  94. // This forces a server probe immediately.
  95. g_InstallData.szIdwlogServer[0] = TEXT('\0');
  96. if (FALSE == ServerWriteMinimum (&g_InstallData, &md)) {
  97. dwError = FALSE;
  98. __leave;
  99. }
  100. }
  101. }
  102. dwError = TRUE;
  103. }
  104. __finally {
  105. // We should delete the shortcut to idwlog from startup group.
  106. Idwlog(TEXT("ENDED ---- [IDWLOG: Stage2 - Service]\n"));
  107. CloseIdwlogDebugFile();
  108. StopService();
  109. }
  110. return dwError;
  111. }
  112. /******************************
  113. #if _MSC_FULL_VER >= 13008827
  114. #pragma warning(pop)
  115. #endif
  116. ******************************/
  117. BOOL
  118. InitService()
  119. // Initializes the service by starting its thread
  120. {
  121. DWORD dw;
  122. // Start the service's thread
  123. g_hThread = CreateThread(0,
  124. 0,
  125. (LPTHREAD_START_ROUTINE)ServiceThread,
  126. 0,
  127. 0,
  128. &dw);
  129. if (g_hThread==0)
  130. return FALSE;
  131. else{
  132. bRunning = TRUE;
  133. return TRUE;
  134. }
  135. }
  136. VOID
  137. ResumeService()
  138. // Resumes a paused service
  139. {
  140. bPause = FALSE;
  141. ResumeThread(g_hThread);
  142. }
  143. VOID
  144. PauseService()
  145. // Pauses the service
  146. {
  147. bPause = TRUE;
  148. SuspendThread(g_hThread);
  149. }
  150. VOID
  151. StopService()
  152. // Stops the service by allowing ServiceMain to
  153. // complete
  154. {
  155. bRunning = FALSE;
  156. // Set the event that is holding ServiceMain
  157. // so that ServiceMain can return
  158. SetEvent(terminateEvent);
  159. }
  160. BOOL
  161. SendStatusToSCM ( DWORD dwCurrentState,
  162. DWORD dwWin32ExitCode,
  163. DWORD dwServiceSpecificExitCode,
  164. DWORD dwCheckPoint,
  165. DWORD dwWaitHint)
  166. /*
  167. This function consolidates the activities of
  168. updating the service status with
  169. SetServiceStatus
  170. */
  171. {
  172. BOOL success;
  173. SERVICE_STATUS serviceStatus;
  174. ZeroMemory (&serviceStatus, sizeof(serviceStatus));
  175. // Fill in all of the SERVICE_STATUS fields
  176. serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  177. serviceStatus.dwCurrentState = dwCurrentState;
  178. // If in the process of something, then accept
  179. // no control events, else accept anything
  180. if (dwCurrentState == SERVICE_START_PENDING)
  181. serviceStatus.dwControlsAccepted = 0;
  182. else
  183. serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  184. SERVICE_ACCEPT_PAUSE_CONTINUE |
  185. SERVICE_ACCEPT_SHUTDOWN;
  186. // if a specific exit code is defines, set up
  187. // the win32 exit code properly
  188. if (dwServiceSpecificExitCode == 0)
  189. serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
  190. else
  191. serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  192. serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
  193. serviceStatus.dwCheckPoint = dwCheckPoint;
  194. serviceStatus.dwWaitHint = dwWaitHint;
  195. // Pass the status record to the SCM
  196. success = SetServiceStatus (serviceStatusHandle,&serviceStatus);
  197. if (!success)
  198. StopService();
  199. return success;
  200. }
  201. VOID
  202. ServiceCtrlHandler (DWORD controlCode)
  203. /*++
  204. Copyright (c) 2000, Microsoft.
  205. Author: Wally W. Ho (wallyho)
  206. Date: 7/31/2000
  207. Routine Description:
  208. This handles events received from the service control manager.
  209. Arguments:
  210. Standard control codes for a service of:
  211. SERVICE_CONTROL_STOP;
  212. SERVICE_CONTROL_PAUSE;
  213. SERVICE_CONTROL_CONTINUE;
  214. SERVICE_CONTROL_INTERROGATE;
  215. SERVICE_CONTROL_SHUTDOWN;
  216. Return Value:
  217. NONE
  218. --*/
  219. {
  220. DWORD currentState = 0;
  221. BOOL success;
  222. switch (controlCode) {
  223. // Stop the service
  224. case SERVICE_CONTROL_STOP:
  225. currentState = SERVICE_STOP_PENDING;
  226. success = SendStatusToSCM(SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);
  227. // Stop the service
  228. StopService();
  229. return ;
  230. // Pause the service
  231. case SERVICE_CONTROL_PAUSE:
  232. if (bRunning && !bPause) {
  233. success = SendStatusToSCM(SERVICE_PAUSE_PENDING,NO_ERROR, 0, 1, 1000);
  234. PauseService();
  235. currentState = SERVICE_PAUSED;
  236. }
  237. break;
  238. // Resume from a pause
  239. case SERVICE_CONTROL_CONTINUE:
  240. if (bRunning && bPause) {
  241. success = SendStatusToSCM( SERVICE_CONTINUE_PENDING,NO_ERROR, 0, 1, 1000);
  242. ResumeService();
  243. currentState = SERVICE_RUNNING;
  244. }
  245. break;
  246. // Update current status
  247. case SERVICE_CONTROL_INTERROGATE:
  248. break;
  249. case SERVICE_CONTROL_SHUTDOWN:
  250. // Do nothing on shutdown
  251. return ;
  252. default:
  253. break;
  254. }
  255. SendStatusToSCM(currentState, NO_ERROR, 0, 0, 0);
  256. }
  257. VOID
  258. Terminate(DWORD error)
  259. /*++
  260. Handle an error from ServiceMain by cleaning up
  261. and telling SCM that the service didn't start.
  262. --*/
  263. {
  264. // if terminateEvent has been created, close it.
  265. if (terminateEvent)
  266. CloseHandle(terminateEvent);
  267. // Send a message to the scm to tell about stoppage
  268. if (serviceStatusHandle)
  269. SendStatusToSCM(SERVICE_STOPPED, error,0, 0, 0);
  270. // If the thread has started kill it off
  271. if (g_hThread)
  272. CloseHandle(g_hThread);
  273. // Do not need to close serviceStatusHandle
  274. }
  275. VOID
  276. ServiceMain(DWORD argc, LPTSTR *argv)
  277. /*++
  278. Copyright (c) 2000, Microsoft.
  279. Author: Wally W. Ho (wallyho)
  280. Date: 8/2/2000
  281. Routine Description:
  282. ServiceMain is called when the SCM wants to start the service.
  283. When it returns, the service has stopped. It therefore waits
  284. on an event just before the end of the function, and that event
  285. gets set when it is time to stop. It also returns on any error
  286. because the service cannot start if there is an error.
  287. Arguments:
  288. Normal arguments like Main would have.
  289. Return Value:
  290. NONE
  291. --*/
  292. {
  293. BOOL success;
  294. __try{
  295. // Call Registration function
  296. serviceStatusHandle =
  297. RegisterServiceCtrlHandler( SCM_DISPLAY_NAME,(LPHANDLER_FUNCTION)ServiceCtrlHandler);
  298. if (!serviceStatusHandle) __leave;
  299. // Notify SCM of progress
  300. success = SendStatusToSCM( SERVICE_START_PENDING, NO_ERROR, 0, 1, 5000);
  301. if (!success) __leave;
  302. // create the termination event
  303. terminateEvent = CreateEvent (0, TRUE, FALSE,0);
  304. if (!terminateEvent) __leave;
  305. // Notify SCM of progress
  306. success = SendStatusToSCM( SERVICE_START_PENDING, NO_ERROR, 0, 3, 5000);
  307. if (!success) __leave;
  308. // Start the service itself
  309. success = InitService();
  310. if (!success) __leave;
  311. // The service is now running. Notify SCM of progress
  312. success = SendStatusToSCM(SERVICE_RUNNING,NO_ERROR, 0, 0, 0);
  313. if (!success) __leave;
  314. // Wait for stop signal, and then terminate
  315. WaitForSingleObject (terminateEvent, INFINITE);
  316. // Tag the file to be removed after running.
  317. OpenIdwlogDebugFile(WRITE_SERVICE_DBG);
  318. RemoveService( SCM_SERVICE_NAME );
  319. CloseIdwlogDebugFile();
  320. SetLastError(0);
  321. }
  322. __finally {
  323. // Final Clean Up.
  324. Terminate(GetLastError());
  325. }
  326. }
  327. BOOL
  328. InstallService( LPTSTR szServiceNameSCM,
  329. LPTSTR szServiceLabel,
  330. LPTSTR szExeFullPath)
  331. /*++
  332. Copyright (c) 2000, Microsoft.
  333. Author: Wally W. Ho (wallyho)
  334. Date: 7/27/2000
  335. Routine Description:
  336. This installs a service.
  337. Arguments:
  338. szServiceNameSCM is the name used internally by the SCM\n";
  339. szServiceLabel is the name that appears in the Services applet\n";
  340. szExeFullPath ie. eg "c:\winnt\xxx.exe"
  341. Return Value:
  342. NONE
  343. --*/
  344. {
  345. SC_HANDLE newScm;
  346. Idwlog(TEXT("Installing a new service\n"));
  347. // open a connection to the SCM
  348. SC_HANDLE scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
  349. if (!scm)
  350. Idwlog(TEXT("In OpenScManager: Error %lu\n"),GetLastError());
  351. newScm = CreateService( scm,
  352. szServiceNameSCM,
  353. szServiceLabel,
  354. SERVICE_ALL_ACCESS,
  355. SERVICE_WIN32_OWN_PROCESS,
  356. SERVICE_AUTO_START,
  357. SERVICE_ERROR_NORMAL,
  358. szExeFullPath,
  359. NULL,
  360. NULL,
  361. NULL,
  362. NULL,
  363. NULL);
  364. if (!newScm){
  365. Idwlog(TEXT("Problem installing Service: Error %lu.\n"),GetLastError());
  366. CloseServiceHandle(scm);
  367. return FALSE;
  368. }
  369. else
  370. Idwlog(TEXT("Finished installing a new service.\n"));
  371. // clean up
  372. CloseServiceHandle(newScm);
  373. CloseServiceHandle(scm);
  374. return TRUE;
  375. }
  376. BOOL
  377. RemoveService( IN LPTSTR szServiceNameSCM)
  378. /*++
  379. Copyright (c) 2000, Microsoft.
  380. Author: Wally W. Ho (wallyho)
  381. Date: 7/27/2000
  382. Routine Description:
  383. This function removes the specified service from the machine.
  384. Arguments:
  385. The service to remove's internal name.
  386. Return Value:
  387. TRUE on success
  388. FALSE on failure
  389. --*/
  390. {
  391. SC_HANDLE service, scm;
  392. BOOL success;
  393. SERVICE_STATUS status;
  394. Idwlog(TEXT("Removing the %s service.\n"), szServiceNameSCM);
  395. // open a connection to the SCM
  396. scm = OpenSCManager(NULL,
  397. NULL,
  398. SC_MANAGER_ALL_ACCESS);
  399. if (!scm)
  400. Idwlog(TEXT("In OpenScManager: Error %lu\n"),GetLastError());
  401. // Get the service's handle
  402. service = OpenService(scm,
  403. szServiceNameSCM,
  404. DELETE);
  405. if (!service)
  406. Idwlog(TEXT("In OpenService: Error %lu\n"),GetLastError());
  407. // Stop the service if necessary
  408. success = QueryServiceStatus(service, &status);
  409. if (!success)
  410. Idwlog(TEXT("In QueryServiceStatus: Error %lu\n"),GetLastError());
  411. if (status.dwCurrentState != SERVICE_STOPPED){
  412. Idwlog(TEXT("Stopping Service...\n"));
  413. success = ControlService(service,
  414. SERVICE_CONTROL_STOP,
  415. &status);
  416. if (!success)
  417. Idwlog(TEXT("In ControlService: Error %lu\n"),GetLastError());
  418. Sleep(500);
  419. }
  420. // Remove the service
  421. success = DeleteService(service);
  422. if (success)
  423. Idwlog(TEXT("Finished Deleting Service.\n"));
  424. else {
  425. Idwlog(TEXT("Problem Deleting Service: Error %lu.\n"),GetLastError());
  426. if ( ERROR_SERVICE_MARKED_FOR_DELETE == GetLastError()) {
  427. Idwlog(TEXT(" This service is already marked for delete.\n"));
  428. }
  429. }
  430. // clean up
  431. CloseServiceHandle(service);
  432. CloseServiceHandle(scm);
  433. return TRUE;
  434. }