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.

1149 lines
28 KiB

  1. /*--------------------------------------------------------------
  2. *
  3. * FILE: SKeys.c
  4. *
  5. * PURPOSE: The main interface routines between the service
  6. * manager and the Serial Keys program.
  7. *
  8. * CREATION: June 1994
  9. *
  10. * COPYRIGHT: Black Diamond Software (C) 1994
  11. *
  12. * AUTHOR: Ronald Moak
  13. *
  14. * NOTES:
  15. *
  16. * This file, and all others associated with it contains trade secrets
  17. * and information that is proprietary to Black Diamond Software.
  18. * It may not be copied copied or distributed to any person or firm
  19. * without the express written permission of Black Diamond Software.
  20. * This permission is available only in the form of a Software Source
  21. * License Agreement.
  22. *
  23. * $Header: %Z% %F% %H% %T% %I%
  24. *
  25. *--- Includes ---------------------------------------------------------*/
  26. #include <windows.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <process.h>
  30. #include <tchar.h>
  31. #include "vars.h"
  32. #include "w95trace.c"
  33. #define DEFDATA 1
  34. #include "sk_defs.h"
  35. #include "sk_comm.h"
  36. #include "sk_reg.h"
  37. #include "sk_dll.h"
  38. #include "sk_login.h"
  39. #include "sk_ex.h"
  40. #include "..\skdll\skeys.h"
  41. #define LONGSTRINGSIZE 1024
  42. #define WAITMAX 0x7FFFFFFF
  43. #define RUNNINGEVENT TEXT("SkeysRunning")
  44. #if defined(DEBUG) && 0
  45. // give us a long time to startup in case we're debugging
  46. #define WAITSTARTUP WAITMAX
  47. #else
  48. // normal startup time
  49. #define WAITSTARTUP 60000
  50. #endif
  51. // --- Local Variables --------------------------------------------------
  52. static SERVICE_STATUS_HANDLE s_sshStatusHandle;
  53. static SERVICE_STATUS s_ssStatus; // current status of the service
  54. PTSTR SERVICENAME = TEXT("SerialKeys");
  55. PTSTR SKEYSUSERINITCMD = TEXT("SKEYS /I");
  56. PTSTR WINLOGONPATH = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon");
  57. PTSTR USERINIT = TEXT("Userinit");
  58. PTSTR USERINITCMDSEP = TEXT(",");
  59. DWORD s_dwServiceCommand;
  60. static HANDLE s_hEventServiceRequest = NULL;
  61. static HANDLE s_hEventServiceRequestReady = NULL;
  62. static HANDLE s_hEventServiceTerminate = NULL;
  63. static HANDLE s_hEventSkeysServiceRunning = NULL;
  64. void DoService();
  65. void DoInit();
  66. void InstallUserInit();
  67. BOOL IsSerialKeysAutoStart();
  68. //--- SCM Function Prototypes ------------------------------------------------
  69. //
  70. // Note: The following fuctions manage the connection of the service
  71. // with the Service Contol Manager.
  72. void PostEventLog(LPTSTR lpszMsg,DWORD Error);
  73. VOID ServiceMain(DWORD dwArgc, LPTSTR *ppszArgv);
  74. VOID StopSerialKeys(LPTSTR lpszMsg);
  75. BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
  76. DWORD dwWin32ExitCode,
  77. DWORD dwCheckPoint,
  78. DWORD dwWaitHint);
  79. LPHANDLER_FUNCTION ServiceCtrl(DWORD dwCtrlCode);
  80. // Service Routines -----------------------------------------------
  81. //
  82. // Note: The following fuctions manage the internal control of the
  83. // Service
  84. static void InitReg();
  85. static BOOL InitService();
  86. static void PauseService();
  87. static void ProcessService();
  88. static void ResumeService();
  89. static void TerminateService();
  90. static void ProcessLogout(DWORD dwCtrlType);
  91. static BOOL InstallLogout();
  92. static BOOL TerminateLogout();
  93. static void EnableService(BOOL fOn);
  94. // CONSIDER - Removing this code. It only gets executed when SKeys is
  95. // run from the command line. When run as a service, ServiceMain is
  96. // called when the service is started. The sources file pulls in
  97. // winmain from the runtime lib. DoInit and DoService could also be
  98. // removed with _tWinMain.
  99. int WINAPI _tWinMain(
  100. HINSTANCE hInstance,
  101. HINSTANCE hPrevInstance,
  102. PTSTR pszCmdLine,
  103. int nCmdShow)
  104. {
  105. if ((TEXT('/') == pszCmdLine[0] || TEXT('-') == pszCmdLine[0]) &&
  106. (TEXT('I') == pszCmdLine[1] || TEXT('i') == pszCmdLine[1]))
  107. {
  108. DoInit();
  109. }
  110. else
  111. {
  112. DoService();
  113. }
  114. ExitProcess(0);
  115. return(0);
  116. }
  117. /*---------------------------------------------------------------
  118. *
  119. * FUNCTION DoInit()
  120. *
  121. * TYPE Global
  122. *
  123. * PURPOSE This function is called to read skeys configuration
  124. * from HKEY_CURRENT_USER at logon session startup and
  125. * send the information to the service
  126. *
  127. * INPUTS None
  128. *
  129. * RETURNS None
  130. *
  131. *---------------------------------------------------------------*/
  132. void DoInit()
  133. {
  134. HANDLE hEventSkeysServiceRunning = NULL;
  135. PSECURITY_DESCRIPTOR pSD;
  136. SECURITY_ATTRIBUTES sa;
  137. pSD = CreateSd(SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE);
  138. if (pSD)
  139. {
  140. sa.nLength = sizeof(sa);
  141. sa.bInheritHandle = TRUE;
  142. sa.lpSecurityDescriptor = pSD;
  143. hEventSkeysServiceRunning = CreateEvent(
  144. &sa, // Security
  145. TRUE, // Manual reset?
  146. FALSE, // initial state - not signaled
  147. RUNNINGEVENT); // name
  148. free(pSD);
  149. }
  150. if (NULL != hEventSkeysServiceRunning)
  151. {
  152. DWORD dwWait;
  153. dwWait = WaitForSingleObject(hEventSkeysServiceRunning, 60 * 1000);
  154. if (WAIT_OBJECT_0 == dwWait)
  155. {
  156. SKEY_SystemParametersInfo((UINT)SK_SPI_INITUSER, 0, NULL, 0);
  157. }
  158. CloseHandle(hEventSkeysServiceRunning);
  159. }
  160. return;
  161. }
  162. /*---------------------------------------------------------------
  163. *
  164. * SCM Interface Functions
  165. *
  166. /*---------------------------------------------------------------
  167. *
  168. * FUNCTION DoService()
  169. *
  170. * TYPE Global
  171. *
  172. * PURPOSE all DoService does is call StartServiceCtrlDispatcher
  173. * to register the main service thread. When the
  174. * API returns, the service has stopped, so exit.
  175. *
  176. * INPUTS None
  177. *
  178. * RETURNS None
  179. *
  180. *---------------------------------------------------------------*/
  181. void DoService()
  182. {
  183. SERVICE_TABLE_ENTRY dispatchTable[] =
  184. {
  185. { SERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain },
  186. { NULL, NULL }
  187. };
  188. PSECURITY_DESCRIPTOR pSD;
  189. SECURITY_ATTRIBUTES sa;
  190. s_hEventServiceRequest = CreateEvent(
  191. NULL, // Security
  192. FALSE, // Manual reset?
  193. FALSE, // initial state - not signaled
  194. NULL); // name
  195. s_hEventServiceRequestReady = CreateEvent(
  196. NULL, // Security
  197. FALSE, // Manual reset?
  198. TRUE, // initial state - signaled (can accept one request even before ready)
  199. NULL); // name
  200. s_hEventServiceTerminate = CreateEvent(
  201. NULL, // Security
  202. TRUE, // Manual reset?
  203. FALSE, // initial state - not signaled
  204. NULL); // name
  205. s_hEventSkeysServiceRunning = NULL;
  206. pSD = CreateSd(SYNCHRONIZE|EVENT_MODIFY_STATE|GENERIC_READ|GENERIC_WRITE);
  207. DBPRINTF(TEXT("DoService: CreateSd %s\r\n"), (pSD)?TEXT("Succeeded"):TEXT("Failed"));
  208. if (pSD)
  209. {
  210. sa.nLength = sizeof(sa);
  211. sa.bInheritHandle = TRUE;
  212. sa.lpSecurityDescriptor = pSD;
  213. s_hEventSkeysServiceRunning = CreateEvent(
  214. &sa, // Security
  215. TRUE, // Manual reset?
  216. FALSE, // initial state - not signaled
  217. RUNNINGEVENT); // name
  218. free(pSD);
  219. }
  220. if (NULL != s_hEventServiceRequest &&
  221. NULL != s_hEventServiceRequestReady &&
  222. NULL != s_hEventServiceTerminate &&
  223. NULL != s_hEventSkeysServiceRunning)
  224. {
  225. DBPRINTF(TEXT("DoService: calling StartServiceCtrlDispatcher... \r\n"));
  226. if (!StartServiceCtrlDispatcher(dispatchTable))
  227. {
  228. DBPRINTF(TEXT("DoService: StartServiceCtrlDispatcher FAILED\r\n"));
  229. StopSerialKeys(TEXT("StartServiceCtrlDispatcher failed."));
  230. }
  231. }
  232. else
  233. {
  234. DBPRINTF(TEXT("DoService: Unable to create event %p %p %p %p\r\n"), s_hEventServiceRequest, s_hEventServiceRequestReady, s_hEventServiceTerminate, s_hEventSkeysServiceRunning);
  235. StopSerialKeys(TEXT("Unable to create event."));
  236. }
  237. if (NULL != s_hEventServiceRequest)
  238. {
  239. CloseHandle(s_hEventServiceRequest);
  240. }
  241. if (NULL != s_hEventServiceRequestReady)
  242. {
  243. CloseHandle(s_hEventServiceRequestReady);
  244. }
  245. if (NULL != s_hEventServiceTerminate)
  246. {
  247. CloseHandle(s_hEventServiceTerminate);
  248. }
  249. if (NULL != s_hEventSkeysServiceRunning)
  250. {
  251. ResetEvent(s_hEventSkeysServiceRunning);
  252. CloseHandle(s_hEventSkeysServiceRunning);
  253. }
  254. }
  255. /*---------------------------------------------------------------
  256. *
  257. * FUNCTION ServiceMain()
  258. *
  259. * TYPE Global
  260. *
  261. * PURPOSE this function takes care of actually starting the service,
  262. * informing the service controller at each step along the way.
  263. * After launching the worker thread, it waits on the event
  264. * that the worker thread will signal at its termination.
  265. *
  266. * INPUTS None
  267. *
  268. * RETURNS None
  269. *
  270. *---------------------------------------------------------------*/
  271. VOID ServiceMain(DWORD dwArgc, LPTSTR *ppszArgv)
  272. {
  273. DBPRINTF(TEXT("ServiceMain()\r\n"));
  274. //
  275. // SERVICE_STATUS members that don't change
  276. s_ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  277. s_ssStatus.dwServiceSpecificExitCode = 0;
  278. //
  279. // register our service control handler:
  280. s_sshStatusHandle = RegisterServiceCtrlHandler(
  281. SERVICENAME,
  282. (LPHANDLER_FUNCTION) ServiceCtrl);
  283. if (!s_sshStatusHandle)
  284. {
  285. TerminateService(GetLastError());
  286. return;
  287. }
  288. // report the status to Service Control Manager.
  289. ReportStatusToSCMgr(
  290. SERVICE_START_PENDING, // service state
  291. NO_ERROR, // exit code
  292. 1, // checkpoint
  293. WAITSTARTUP); // wait hint
  294. #if defined(DEBUG) && 0 /////////////////////////////////////////////////
  295. // This debug code gives us time to attach a debugger
  296. {
  297. int i;
  298. for (i = 0; i < 180; i++) // 180 sec = 3 min
  299. {
  300. Sleep(1000); // one second
  301. }
  302. }
  303. #endif ////////////////////////////////////////////////////////
  304. InitReg();
  305. GetUserValues(REG_DEF);
  306. ////EnableService(skNewKey.dwFlags & SERKF_SERIALKEYSON);
  307. if (!InitService()) // Did Service Initiate successfully?
  308. {
  309. TerminateService(GetLastError()); // No Terminate With Error
  310. return;
  311. }
  312. ReportStatusToSCMgr( // report status to service manager.
  313. SERVICE_RUNNING, // service state
  314. NO_ERROR, // exit code
  315. 0, // checkpoint
  316. 0); // wait hint
  317. SetEvent(s_hEventSkeysServiceRunning);
  318. ProcessService(); // Process the Service
  319. TerminateService(0); // Terminate
  320. return;
  321. }
  322. BOOL IsSerialKeysAutoStart()
  323. {
  324. BOOL fAutoStart = FALSE;
  325. BOOL fOk;
  326. SC_HANDLE schService = NULL;
  327. SC_HANDLE schSCManager = NULL;
  328. schSCManager = OpenSCManager( // Open Service Manager
  329. NULL, // machine (NULL == local)
  330. NULL, // database (NULL == default)
  331. MAXIMUM_ALLOWED);
  332. if (NULL != schSCManager) // Did Open Service succeed?
  333. {
  334. schService = OpenService(
  335. schSCManager ,
  336. __TEXT("SerialKeys"),
  337. MAXIMUM_ALLOWED);
  338. if (NULL != schService)
  339. {
  340. BYTE abServiceConfig[1024];
  341. LPQUERY_SERVICE_CONFIG pqsc = (LPQUERY_SERVICE_CONFIG)abServiceConfig;
  342. DWORD cbBytesNeeded;
  343. fOk = QueryServiceConfig(
  344. schService,
  345. pqsc,
  346. sizeof(abServiceConfig),
  347. &cbBytesNeeded);
  348. if (fOk)
  349. {
  350. fAutoStart = (SERVICE_AUTO_START == pqsc->dwStartType);
  351. }
  352. CloseServiceHandle(schService);
  353. }
  354. CloseServiceHandle(schSCManager);
  355. }
  356. return fAutoStart;
  357. }
  358. void InstallUserInit()
  359. {
  360. BOOL fOk = FALSE;
  361. HKEY hkey;
  362. LONG lErr;
  363. DWORD dwType;
  364. TCHAR szUserinit[LONGSTRINGSIZE];
  365. DWORD cbData = sizeof(szUserinit);
  366. lErr = RegOpenKeyEx(
  367. HKEY_LOCAL_MACHINE,
  368. WINLOGONPATH,
  369. REG_OPTION_NON_VOLATILE,
  370. KEY_ALL_ACCESS,
  371. &hkey);
  372. if (ERROR_SUCCESS == lErr)
  373. {
  374. lErr = RegQueryValueEx(
  375. hkey,
  376. USERINIT,
  377. 0,
  378. &dwType,
  379. (LPBYTE)szUserinit,
  380. &cbData);
  381. szUserinit[LONGSTRINGSIZE-1]='\0';
  382. if (ERROR_SUCCESS == lErr && dwType == REG_SZ)
  383. {
  384. // check to see if we are already installed and if we have
  385. // enough room to install
  386. // the + 2 allows for the terminating null and for the command seperator char
  387. if (NULL == _tcsstr(szUserinit, SKEYSUSERINITCMD) &&
  388. lstrlen(szUserinit) + lstrlen(SKEYSUSERINITCMD) + 2 <
  389. ARRAY_SIZE(szUserinit))
  390. {
  391. lstrcat(szUserinit, USERINITCMDSEP);
  392. lstrcat(szUserinit, SKEYSUSERINITCMD);
  393. RegSetValueEx(
  394. hkey,
  395. USERINIT,
  396. 0,
  397. REG_SZ,
  398. (CONST LPBYTE)szUserinit,
  399. (lstrlen(szUserinit) + 1) *
  400. sizeof(*szUserinit));
  401. }
  402. }
  403. RegCloseKey(hkey);
  404. }
  405. return;
  406. }
  407. void RemoveUserInit()
  408. {
  409. BOOL fOk = FALSE;
  410. HKEY hkey;
  411. LONG lErr;
  412. DWORD dwType;
  413. TCHAR szUserinit[LONGSTRINGSIZE];
  414. PTSTR pszDest;
  415. PTSTR pszSrc;
  416. DWORD cbData = sizeof(szUserinit);
  417. lErr = RegOpenKeyEx(
  418. HKEY_LOCAL_MACHINE,
  419. WINLOGONPATH,
  420. REG_OPTION_NON_VOLATILE,
  421. KEY_ALL_ACCESS,
  422. &hkey);
  423. if (ERROR_SUCCESS == lErr)
  424. {
  425. lErr = RegQueryValueEx(
  426. hkey,
  427. USERINIT,
  428. 0,
  429. &dwType,
  430. (LPBYTE)szUserinit,
  431. &cbData);
  432. szUserinit[LONGSTRINGSIZE-1]='\0';
  433. if (ERROR_SUCCESS == lErr && dwType == REG_SZ)
  434. {
  435. // check to see if we are already installed
  436. pszDest = _tcsstr(szUserinit, SKEYSUSERINITCMD);
  437. if (NULL != pszDest)
  438. {
  439. pszSrc =_tcsstr(pszDest, USERINITCMDSEP);
  440. if (NULL != pszSrc)
  441. {
  442. _tcscpy(pszDest, pszSrc+1);
  443. }
  444. else
  445. {
  446. while(szUserinit < pszDest && *SKEYSUSERINITCMD != *pszDest)
  447. {
  448. --pszDest;
  449. }
  450. *pszDest = 0; // null terminate
  451. }
  452. }
  453. RegSetValueEx(
  454. hkey,
  455. USERINIT,
  456. 0,
  457. REG_SZ,
  458. (CONST LPBYTE)szUserinit,
  459. (lstrlen(szUserinit) + 1) *
  460. sizeof(*szUserinit));
  461. }
  462. RegCloseKey(hkey);
  463. }
  464. return;
  465. }
  466. static void EnableService(BOOL fOn)
  467. {
  468. SC_HANDLE schService = NULL;
  469. SC_HANDLE schSCManager = NULL;
  470. schSCManager = OpenSCManager( // Open Service Manager
  471. NULL, // machine (NULL == local)
  472. NULL, // database (NULL == default)
  473. MAXIMUM_ALLOWED);
  474. if (NULL != schSCManager) // Did Open Service succeed?
  475. {
  476. schService = OpenService(
  477. schSCManager ,
  478. __TEXT("SerialKeys"),
  479. SERVICE_CHANGE_CONFIG | SERVICE_STOP);
  480. if (NULL != schService)
  481. {
  482. ChangeServiceConfig(
  483. schService,
  484. SERVICE_WIN32_OWN_PROCESS,
  485. (fOn) ? SERVICE_AUTO_START : SERVICE_DEMAND_START,
  486. SERVICE_NO_CHANGE, // severity if service fails to start
  487. NULL, // pointer to service binary file name
  488. NULL, // pointer to load ordering group name
  489. NULL, // pointer to variable to get tag identifier
  490. NULL, // pointer to array of dependency names
  491. NULL, // pointer to account name of service
  492. NULL, // pointer to password for service account
  493. __TEXT("SerialKeys")); // name to display
  494. CloseServiceHandle(schService);
  495. }
  496. CloseServiceHandle(schSCManager);
  497. }
  498. if (fOn)
  499. {
  500. InstallUserInit();
  501. }
  502. else
  503. {
  504. RemoveUserInit();
  505. }
  506. return;
  507. }
  508. //---------------------------------------------------------------
  509. //
  510. // FUNCTION void ServiceCtrl(DWORD dwCtrlCode)
  511. //
  512. // TYPE Global
  513. //
  514. // PURPOSE this function is called by the Service Controller whenever
  515. // someone calls ControlService in reference to our service.
  516. //
  517. // INPUTS DWORD dwCtrlCode -
  518. //
  519. // RETURNS None
  520. //
  521. //-----------------------------------------------------------------
  522. LPHANDLER_FUNCTION ServiceCtrl(DWORD dwCtrlCode)
  523. {
  524. DWORD dwState = SERVICE_RUNNING;
  525. DWORD dwWait = 0;
  526. DBPRINTF(TEXT("ServiceCtrl()\r\n"));
  527. // Handle the requested control code.
  528. switch(dwCtrlCode)
  529. {
  530. case SERVICE_CONTROL_PAUSE: // Pause the service if it is running.
  531. if (s_ssStatus.dwCurrentState == SERVICE_RUNNING)
  532. {
  533. PauseService();
  534. dwState = SERVICE_PAUSED;
  535. }
  536. break;
  537. case SERVICE_CONTROL_CONTINUE: // Resume the paused service.
  538. if (s_ssStatus.dwCurrentState == SERVICE_PAUSED)
  539. {
  540. ResumeService();
  541. dwState = SERVICE_RUNNING;
  542. }
  543. break;
  544. case SERVICE_CONTROL_STOP: // Stop the service.
  545. // Report the status, specifying the checkpoint and waithint,
  546. // before setting the termination event.
  547. if (s_ssStatus.dwCurrentState == SERVICE_RUNNING)
  548. {
  549. dwState = SERVICE_STOP_PENDING;
  550. dwWait = 20000;
  551. SetEvent(s_hEventServiceTerminate);
  552. }
  553. break;
  554. case SERVICE_CONTROL_INTERROGATE: // Update the service status.
  555. default: // invalid control code
  556. break;
  557. }
  558. // send a status response.
  559. ReportStatusToSCMgr(dwState, NO_ERROR, 0, dwWait);
  560. return(0);
  561. }
  562. /*---------------------------------------------------------------
  563. *
  564. * FUNCTION BOOL ReportStatusToSCMgr()
  565. *
  566. * TYPE Global
  567. *
  568. * PURPOSE This function is called by the ServMainFunc() and
  569. * ServCtrlHandler() functions to update the service's status
  570. * to the service control manager.
  571. *
  572. * INPUTS DWORD dwCurrentState
  573. * DWORD dwWin32ExitCode
  574. * DWORD dwCheckPoint
  575. * DWORD dwWaitHint
  576. *
  577. * RETURNS None
  578. *
  579. *---------------------------------------------------------------*/
  580. BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
  581. DWORD dwWin32ExitCode,
  582. DWORD dwCheckPoint,
  583. DWORD dwWaitHint)
  584. {
  585. BOOL fResult;
  586. #ifdef DEBUG
  587. {
  588. switch (dwCurrentState)
  589. {
  590. case SERVICE_START_PENDING:
  591. DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_START_PENDING:)\r\n"));
  592. break;
  593. case SERVICE_PAUSED:
  594. DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_PAUSED:)\r\n"));
  595. break;
  596. case SERVICE_CONTINUE_PENDING:
  597. DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_CONTINUE_PENDING:)\r\n"));
  598. break;
  599. case SERVICE_STOP_PENDING:
  600. DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_STOP_PENDING:)\r\n"));
  601. break;
  602. case SERVICE_STOPPED:
  603. DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_STOPPED:)\r\n"));
  604. break;
  605. case SERVICE_RUNNING:
  606. DBPRINTF(TEXT("ReportStatusToSCMgr(SERVICE_RUNNING:)\r\n"));
  607. break;
  608. default:
  609. DBPRINTF(TEXT("ReportStatusToSCMgr(ERROR - SERVICE_UNKNOWN)\r\n"));
  610. break;
  611. }
  612. }
  613. #endif
  614. switch (dwCurrentState)
  615. {
  616. case SERVICE_STOPPED:
  617. case SERVICE_START_PENDING:
  618. case SERVICE_STOP_PENDING:
  619. s_ssStatus.dwControlsAccepted = 0;
  620. break;
  621. default:
  622. s_ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
  623. break;
  624. }
  625. // These SERVICE_STATUS members are set from parameters.
  626. s_ssStatus.dwCurrentState = dwCurrentState;
  627. s_ssStatus.dwWin32ExitCode = dwWin32ExitCode;
  628. s_ssStatus.dwCheckPoint = dwCheckPoint;
  629. s_ssStatus.dwWaitHint = dwWaitHint;
  630. // Report the status of the service to the service control manager.
  631. fResult = SetServiceStatus(
  632. s_sshStatusHandle, // service reference handle
  633. &s_ssStatus); // SERVICE_STATUS structure
  634. if (!fResult)
  635. {
  636. StopSerialKeys(TEXT("SetServiceStatus")); // If an error occurs, stop the service.
  637. }
  638. return fResult;
  639. }
  640. /*---------------------------------------------------------------
  641. *
  642. * FUNCTION void StopSerialKeys(LPTSTR lpszMsg)
  643. *
  644. * TYPE Global
  645. *
  646. * PURPOSE The StopSerialKeys function can be used by any thread
  647. * to report an error, or stop the service.
  648. *
  649. * INPUTS LPTSTR lpszMsg -
  650. *
  651. * RETURNS None
  652. *
  653. *---------------------------------------------------------------*/
  654. VOID StopSerialKeys(LPTSTR lpszMsg)
  655. {
  656. DBPRINTF(TEXT("StopSerialKeys()\r\n"));
  657. PostEventLog(lpszMsg,GetLastError()); // Post to Event Log
  658. SetEvent(s_hEventServiceTerminate);
  659. }
  660. /*---------------------------------------------------------------
  661. *
  662. * FUNCTION void PostEventLog(LPTSTR lpszMsg, DWORD Error)
  663. *
  664. * TYPE Local
  665. *
  666. * PURPOSE This function post strings to the Event Log
  667. *
  668. * INPUTS LPTSTR lpszMsg - String to send
  669. * DWORD Error - Error Code (if 0 no error)
  670. *
  671. * RETURNS None
  672. *
  673. *---------------------------------------------------------------*/
  674. void PostEventLog(LPTSTR lpszMsg,DWORD Error)
  675. {
  676. WORD ErrType = EVENTLOG_INFORMATION_TYPE;
  677. WORD ErrStrings = 0;
  678. TCHAR szMsg[256];
  679. HANDLE hEventSource;
  680. LPTSTR lpszStrings[2];
  681. DBPRINTF(TEXT("PostEventLog()\r\n"));
  682. lpszStrings[0] = lpszMsg;
  683. if (Error)
  684. {
  685. ErrType = EVENTLOG_ERROR_TYPE;
  686. ErrStrings = 2;
  687. wsprintf(szMsg, TEXT("SerialKeys error: %d"), Error);
  688. lpszStrings[0] = szMsg;
  689. lpszStrings[1] = lpszMsg;
  690. }
  691. hEventSource = RegisterEventSource(NULL,SERVICENAME);
  692. if (hEventSource != NULL)
  693. {
  694. ReportEvent
  695. (
  696. hEventSource, // handle of event source
  697. ErrType, // event type
  698. 0, // event category
  699. 0, // event ID
  700. NULL, // current user's SID
  701. ErrStrings, // strings in lpszStrings
  702. 0, // no bytes of raw data
  703. lpszStrings, // array of error strings
  704. NULL // no raw data
  705. );
  706. (VOID) DeregisterEventSource(hEventSource);
  707. }
  708. }
  709. /*---------------------------------------------------------------
  710. *
  711. * Internal Service Control Functions
  712. *
  713. /*---------------------------------------------------------------
  714. *
  715. * FUNCTION void InitService()
  716. *
  717. * PURPOSE This function Initializes the Service & starts the
  718. * major threads of the service.
  719. *
  720. * INPUTS None
  721. *
  722. * RETURNS None
  723. *
  724. *---------------------------------------------------------------*/
  725. static BOOL InitService()
  726. {
  727. DBPRINTF(TEXT("InitService()\r\n"));
  728. InstallLogout();
  729. if (!InitDLL())
  730. return(FALSE);
  731. if (!InitLogin())
  732. return(FALSE);
  733. if (!InitComm())
  734. return(FALSE);
  735. DoServiceCommand(SC_LOG_IN); // Set ProcessService to Login Serial Keys
  736. return(TRUE);
  737. }
  738. static void InitReg()
  739. {
  740. // Set Structure pointers to Buffers
  741. skNewKey.cbSize = sizeof(skNewKey);
  742. skNewKey.lpszActivePort = szNewActivePort;
  743. skNewKey.lpszPort = szNewPort;
  744. skCurKey.cbSize = sizeof(skCurKey);
  745. skCurKey.lpszActivePort = szCurActivePort;
  746. skCurKey.lpszPort = szCurPort;
  747. // Set Default Values
  748. skNewKey.dwFlags = SERKF_AVAILABLE;
  749. skNewKey.iBaudRate = 300;
  750. skNewKey.iPortState = 2;
  751. lstrcpy(szNewPort,TEXT("COM1:"));
  752. lstrcpy(szNewActivePort,TEXT("COM1:"));
  753. }
  754. /*---------------------------------------------------------------
  755. *
  756. * FUNCTION void PauseService()
  757. *
  758. * PURPOSE This function is called to pause the service
  759. *
  760. * INPUTS None
  761. *
  762. * RETURNS None
  763. *
  764. *---------------------------------------------------------------*/
  765. static void PauseService()
  766. {
  767. DBPRINTF(TEXT("PauseService()\r\n"));
  768. SuspendDLL();
  769. SuspendComm();
  770. SuspendLogin();
  771. }
  772. /*---------------------------------------------------------------
  773. *
  774. * FUNCTION void DoServiceCommand()
  775. *
  776. * PURPOSE Passes a command to the service thread
  777. *
  778. * INPUTS None
  779. *
  780. * RETURNS None
  781. *
  782. *---------------------------------------------------------------*/
  783. void DoServiceCommand(DWORD dwServiceCommand)
  784. {
  785. DWORD dwWaitRet;
  786. dwWaitRet = WaitForSingleObject(s_hEventServiceRequestReady, 10*1000);
  787. if (WAIT_OBJECT_0 == dwWaitRet)
  788. {
  789. s_dwServiceCommand = dwServiceCommand;
  790. SetEvent(s_hEventServiceRequest);
  791. }
  792. else
  793. {
  794. DBPRINTF(TEXT("DoServiceCommand - wait failed or timed-out, request ignored\r\n"));
  795. }
  796. }
  797. /*---------------------------------------------------------------
  798. *
  799. * FUNCTION void ProcessService()
  800. *
  801. * PURPOSE This function is the main service thread for Serial
  802. * Keys. Is monitors the status of the other theads
  803. * and responds to their request.
  804. *
  805. * INPUTS None
  806. *
  807. * RETURNS None
  808. *
  809. *---------------------------------------------------------------*/
  810. static void ProcessService()
  811. {
  812. DWORD dwServiceCommand;
  813. DWORD dwWaitRet;
  814. typedef enum {
  815. iheventServiceRequest,
  816. iheventServiceTerminate
  817. };
  818. HANDLE ahevent[2] = {s_hEventServiceRequest, s_hEventServiceTerminate};
  819. DBPRINTF(TEXT("ProcessService()\r\n"));
  820. dwWaitRet = WaitForMultipleObjects(ARRAY_SIZE(ahevent), ahevent,
  821. FALSE, // wait all?
  822. INFINITE);
  823. // This loop will terminate when iheventServiceTerminate is signaled or
  824. // WaitForMultipleObjects fails
  825. while (iheventServiceRequest == dwWaitRet - WAIT_OBJECT_0)
  826. {
  827. dwServiceCommand = s_dwServiceCommand;
  828. SetEvent(s_hEventServiceRequestReady);
  829. switch (dwServiceCommand)
  830. {
  831. case SC_LOG_OUT: // Login to New User
  832. DBPRINTF(TEXT("---- User Logging Out\r\n"));
  833. StopComm(); // Stop SerialKey Processing
  834. if(GetUserValues(REG_DEF)) // Get Default values & Do we Start?
  835. {
  836. EnableService(skNewKey.dwFlags & SERKF_SERIALKEYSON);
  837. StartComm(); // Yes - Process SerialKey
  838. }
  839. break;
  840. case SC_LOG_IN: // Login to New User
  841. DBPRINTF(TEXT("---- User Logging In\r\n"));
  842. StopComm(); // Stop SerialKey Processing
  843. if(GetUserValues(REG_DEF))
  844. {
  845. EnableService(skNewKey.dwFlags & SERKF_SERIALKEYSON);
  846. StartComm(); // Yes - Process SerialKey
  847. }
  848. break;
  849. case SC_CHANGE_COMM: // Change Comm Configuration
  850. DBPRINTF(TEXT("---- Making Comm Change\r\n"));
  851. StopComm(); // Stop SerialKey Processing
  852. StartComm(); // Restart SerialKey Processing
  853. break;
  854. case SC_DISABLE_SKEY: // Disable Serial Keys
  855. DBPRINTF(TEXT("---- Disable Serial Keys\r\n"));
  856. StopComm();
  857. break;
  858. case SC_ENABLE_SKEY: // Enable Serial Keys
  859. DBPRINTF(TEXT("---- Enable Serial Keys\r\n"));
  860. StartComm();
  861. break;
  862. }
  863. dwWaitRet = WaitForMultipleObjects(ARRAY_SIZE(ahevent), ahevent,
  864. FALSE, // wait all?
  865. INFINITE);
  866. }
  867. }
  868. /*---------------------------------------------------------------
  869. *
  870. * FUNCTION void ResumeService()
  871. *
  872. * PURPOSE This function is called to restore the service
  873. *
  874. * INPUTS None
  875. *
  876. * RETURNS None
  877. *
  878. *---------------------------------------------------------------*/
  879. static void ResumeService()
  880. {
  881. DBPRINTF(TEXT("ResumeService()\r\n"));
  882. ResumeDLL();
  883. ResumeComm();
  884. ResumeLogin();
  885. }
  886. //---------------------------------------------------------------
  887. //
  888. // FUNCTION void TerminateService(DWORD Error)
  889. //
  890. // TYPE Local
  891. //
  892. // PURPOSE This function is called by ServiceMain to terminate
  893. // the server. It closes all of the open handles &
  894. // and reports the service is stopped.
  895. //
  896. // INPUTS DWORD Error - Any Errors that could abort the
  897. // Service. 0 = Normal Stop
  898. //
  899. // RETURNS None
  900. //
  901. //---------------------------------------------------------------
  902. static void TerminateService(DWORD Error)
  903. {
  904. DBPRINTF(TEXT("TerminateService()\r\n"));
  905. TerminateLogout(); // Remove Logout Monitoring
  906. TerminateComm(); // Init Comm Thread Shutdown
  907. TerminateDLL(); // Init DLL Thread Shutdown
  908. TerminateLogin(); // Init Login Thread Shutdown
  909. // Loop untill all of the Threads are shut down.
  910. while (!DoneLogin()) // Loop until Login Thread is terminated
  911. Sleep(250); // Sleep
  912. while (!DoneDLL()) // Loop until DLL Thread is terminated
  913. Sleep(250); // Sleep
  914. // reload registery values to insure we have the current values
  915. GetUserValues(REG_DEF);
  916. EnableService(skNewKey.dwFlags & SERKF_SERIALKEYSON);
  917. // Report the status is stopped
  918. if (s_sshStatusHandle)
  919. (VOID)ReportStatusToSCMgr(SERVICE_STOPPED,Error,0,0);
  920. }
  921. /*---------------------------------------------------------------
  922. *
  923. * Logout Functions - Process Logout request
  924. *
  925. /*---------------------------------------------------------------
  926. *
  927. * FUNCTION void InstallLogout()
  928. *
  929. * PURPOSE This function installs a Control Handler to process
  930. * logout events.
  931. *
  932. * INPUTS None
  933. *
  934. * RETURNS None
  935. *
  936. *---------------------------------------------------------------*/
  937. static BOOL InstallLogout()
  938. {
  939. DBPRINTF(TEXT("InstallLogout()\r\n"));
  940. return(SetConsoleCtrlHandler((PHANDLER_ROUTINE)ProcessLogout,TRUE));
  941. }
  942. /*---------------------------------------------------------------
  943. *
  944. * FUNCTION void TerminateLogout()
  945. *
  946. * PURPOSE This function Removes a Control Handler to process
  947. * logout events.
  948. *
  949. * INPUTS None
  950. *
  951. * RETURNS None
  952. *
  953. *---------------------------------------------------------------*/
  954. static BOOL TerminateLogout()
  955. {
  956. DBPRINTF(TEXT("TerminateLogout()\r\n"));
  957. return(SetConsoleCtrlHandler((PHANDLER_ROUTINE)ProcessLogout,FALSE));
  958. }
  959. /*---------------------------------------------------------------
  960. *
  961. * FUNCTION void ProcessLogout()
  962. *
  963. * PURPOSE This function processes logout events.
  964. *
  965. * INPUTS None
  966. *
  967. * RETURNS None
  968. *
  969. *---------------------------------------------------------------*/
  970. static void ProcessLogout(DWORD dwCtrlType)
  971. {
  972. DBPRINTF(TEXT("ProcessLogout()\r\n"));
  973. if (dwCtrlType == CTRL_LOGOFF_EVENT)
  974. {
  975. DoServiceCommand(SC_LOG_OUT);
  976. // we'll do this each time the currently logged in user logs out
  977. }
  978. }