lobby.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. // Lobby.cpp : Implementation of WinMain
  2. // Note: Proxy/Stub Information
  3. // To build a separate proxy/stub DLL,
  4. // run nmake -f Lobbyps.mk in the project directory.
  5. #include "pch.h"
  6. CServiceModule _Module;
  7. BEGIN_OBJECT_MAP(ObjectMap)
  8. END_OBJECT_MAP()
  9. LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2)
  10. {
  11. while (p1 != NULL && *p1 != NULL)
  12. {
  13. LPCTSTR p = p2;
  14. while (p != NULL && *p != NULL)
  15. {
  16. if (*p1 == *p)
  17. return CharNext(p1);
  18. p = CharNext(p);
  19. }
  20. p1 = CharNext(p1);
  21. }
  22. return NULL;
  23. }
  24. // Although some of these functions are big they are declared inline since they are only used once
  25. inline HRESULT CServiceModule::RegisterServer(BOOL bRegTypeLib, BOOL bService, char * szAccount, char * szPassword)
  26. {
  27. HRESULT hr = CoInitialize(NULL);
  28. if (FAILED(hr))
  29. return hr;
  30. // Remove any previous service since it may point to
  31. // the incorrect file
  32. Uninstall();
  33. // Add service entries
  34. UpdateRegistryFromResource(IDR_Lobby, TRUE);
  35. // Adjust the AppID for Local Server or Service
  36. CRegKey keyAppID;
  37. LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE);
  38. if (lRes != ERROR_SUCCESS)
  39. return lRes;
  40. CRegKey key;
  41. lRes = key.Open(keyAppID, _T("{EFD52202-45CB-454D-B477-33BC5C29BDF1}"), KEY_WRITE);
  42. if (lRes != ERROR_SUCCESS)
  43. return lRes;
  44. key.DeleteValue(_T("LocalService"));
  45. if (bService)
  46. {
  47. key.SetValue(_T("AllLobby"), _T("LocalService"));
  48. key.SetValue(_T("-Service"), _T("ServiceParameters"));
  49. // Create service
  50. //Install();
  51. InstallService(szAccount, szPassword);
  52. }
  53. // Add object entries
  54. hr = CComModule::RegisterServer(bRegTypeLib);
  55. CoUninitialize();
  56. return hr;
  57. }
  58. /*-------------------------------------------------------------------------
  59. * GetModulePath
  60. *-------------------------------------------------------------------------
  61. * Returns:
  62. * path of AllLobby.exe
  63. */
  64. const char * CServiceModule::GetModulePath()
  65. {
  66. static char * pszLast = NULL;
  67. if (pszLast == NULL)
  68. {
  69. static char szFileName[MAX_PATH + 16];
  70. GetModuleFileName(NULL, szFileName, MAX_PATH);
  71. char* p = strrchr(szFileName, '\\');
  72. if (p)
  73. *(p+1) = 0;
  74. else
  75. {
  76. szFileName[0] = '\\';
  77. szFileName[1] = 0;
  78. }
  79. pszLast = szFileName;
  80. }
  81. return pszLast;
  82. }
  83. /*-------------------------------------------------------------------------
  84. * ReadFromRegistry
  85. *-------------------------------------------------------------------------
  86. * Purpose:
  87. * Read info from the registry
  88. *
  89. * Parameters:
  90. * hk: which key to read from
  91. * bIsString: if false, then item is cosnidered to be a DWORD
  92. * szItem: name of item to read
  93. * pValue: destination of read
  94. * dwDefault: default value can be an int or a pointer to a string
  95. *
  96. * Returns:
  97. * true: iff pValue was set
  98. */
  99. bool CServiceModule::ReadFromRegistry(HKEY & hk, bool bIsString, const char * szItem, void * pValue, DWORD dwDefault, bool bWarnIfMissing)
  100. {
  101. char psz[MAX_PATH] = {""};
  102. DWORD dwSize = (bIsString ? sizeof(psz): sizeof(DWORD));
  103. if (RegQueryValueEx(hk, szItem, NULL, NULL, (BYTE *)psz, &dwSize) != ERROR_SUCCESS ||
  104. (bIsString && psz[0] == 0)) // if blank like what SrvConfig.exe makes
  105. {
  106. if (bIsString)
  107. {
  108. if (dwDefault)
  109. {
  110. strcpy((char*)pValue, (char*)dwDefault);
  111. if(bWarnIfMissing)
  112. LogEvent(EVENTLOG_INFORMATION_TYPE, LE_RegStrMissingDef, szItem, dwDefault);
  113. return true;
  114. }
  115. if(bWarnIfMissing)
  116. LogEvent(EVENTLOG_ERROR_TYPE, LE_RegStrMissingNoDef, szItem);
  117. return false;
  118. }
  119. if(bWarnIfMissing)
  120. LogEvent(EVENTLOG_ERROR_TYPE, LE_RegIntMissingDef, szItem, (DWORD)dwDefault);
  121. *(DWORD*)pValue = dwDefault;
  122. return true;
  123. }
  124. if (bIsString)
  125. strcpy((char*)pValue, psz);
  126. else
  127. *(DWORD*)pValue = *(DWORD*)psz;
  128. return true;
  129. }
  130. inline HRESULT CServiceModule::UnregisterServer()
  131. {
  132. HRESULT hr = CoInitialize(NULL);
  133. if (FAILED(hr))
  134. return hr;
  135. // Remove service entries
  136. UpdateRegistryFromResource(IDR_Lobby, FALSE);
  137. // Remove service
  138. Uninstall();
  139. // Remove object entries
  140. CComModule::UnregisterServer(TRUE);
  141. CoUninitialize();
  142. return S_OK;
  143. }
  144. inline void CServiceModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, UINT nServiceNameID, UINT nServiceDescID, const GUID* plibid)
  145. {
  146. CComModule::Init(p, h, plibid);
  147. m_bService = TRUE;
  148. LoadString(h, nServiceNameID, m_szServiceName, sizeof(m_szServiceName) / sizeof(TCHAR));
  149. LoadString(h, nServiceDescID, m_szServiceDesc, sizeof(m_szServiceDesc) / sizeof(TCHAR));
  150. // set up the initial service status
  151. m_hServiceStatus = NULL;
  152. m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  153. m_status.dwCurrentState = SERVICE_STOPPED;
  154. m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  155. m_status.dwWin32ExitCode = 0;
  156. m_status.dwServiceSpecificExitCode = 0;
  157. m_status.dwCheckPoint = 0;
  158. m_status.dwWaitHint = 0;
  159. }
  160. LONG CServiceModule::Unlock()
  161. {
  162. LONG l = CComModule::Unlock();
  163. if (l == 0 && !m_bService)
  164. PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
  165. return l;
  166. }
  167. BOOL CServiceModule::IsInstalled()
  168. {
  169. BOOL bResult = FALSE;
  170. SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  171. if (hSCM != NULL)
  172. {
  173. SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_QUERY_CONFIG);
  174. if (hService != NULL)
  175. {
  176. bResult = TRUE;
  177. ::CloseServiceHandle(hService);
  178. }
  179. ::CloseServiceHandle(hSCM);
  180. }
  181. return bResult;
  182. }
  183. inline BOOL CServiceModule::Install()
  184. {
  185. if (IsInstalled())
  186. return TRUE;
  187. SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  188. if (hSCM == NULL)
  189. {
  190. MessageBox(NULL, _T("Couldn't open service manager"), m_szServiceName, MB_OK);
  191. return FALSE;
  192. }
  193. // Get the executable file path
  194. TCHAR szFilePath[_MAX_PATH];
  195. ::GetModuleFileName(NULL, szFilePath, _MAX_PATH);
  196. SC_HANDLE hService = ::CreateService(
  197. hSCM, m_szServiceName, m_szServiceDesc,
  198. SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
  199. SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
  200. szFilePath, NULL, NULL, _T("RPCSS\0"), NULL, NULL);
  201. if (hService == NULL)
  202. {
  203. ::CloseServiceHandle(hSCM);
  204. MessageBox(NULL, _T("Couldn't create service"), m_szServiceName, MB_OK);
  205. return FALSE;
  206. }
  207. ::CloseServiceHandle(hService);
  208. ::CloseServiceHandle(hSCM);
  209. return TRUE;
  210. }
  211. ////////////////////////////////////////////////////////////////////////
  212. // InstallService - installs this service into the NT service manager
  213. //
  214. //
  215. BOOL CServiceModule::InstallService(char * szAccount, char * szPassword)
  216. {
  217. SC_HANDLE schMgr;
  218. SC_HANDLE schSvc;
  219. char szPath[512];
  220. schMgr = OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);
  221. if (!schMgr)
  222. {
  223. printf("Unable to open SCManager. Service not installed.\n");
  224. return FALSE;
  225. }
  226. GetModuleFileName(NULL,szPath,sizeof(szPath));
  227. schSvc = CreateService(schMgr,
  228. m_szServiceName,
  229. m_szServiceDesc,
  230. SERVICE_ALL_ACCESS,
  231. SERVICE_WIN32_OWN_PROCESS,
  232. SERVICE_AUTO_START,
  233. SERVICE_ERROR_NORMAL,
  234. szPath,
  235. NULL,
  236. NULL,
  237. _T("RPCSS\0"),
  238. szAccount,
  239. szPassword);
  240. if (!schSvc)
  241. {
  242. ::CloseServiceHandle(schMgr);
  243. MessageBox(NULL, _T("Couldn't create service"), m_szServiceName, MB_OK);
  244. return FALSE;
  245. }
  246. CloseServiceHandle(schSvc);
  247. CloseServiceHandle(schMgr);
  248. printf("%s service installed.\n", m_szServiceName);
  249. if (szAccount)
  250. {
  251. TCUserAccount acct;
  252. acct.Init(szAccount); // example: szAccount == Redmond\federat which was passed in on the cmdline
  253. if (S_OK != acct.HasRight(SE_SERVICE_LOGON_NAME))
  254. {
  255. acct.SetRight(SE_SERVICE_LOGON_NAME);
  256. printf("The account %ls\\%ls has been granted the Logon As A Service right.", acct.GetDomainNameW(), acct.GetUserNameW());
  257. }
  258. }
  259. return TRUE;
  260. }
  261. inline BOOL CServiceModule::Uninstall()
  262. {
  263. if (!IsInstalled())
  264. return TRUE;
  265. SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  266. if (hSCM == NULL)
  267. {
  268. MessageBox(NULL, _T("Couldn't open service manager"), m_szServiceName, MB_OK);
  269. return FALSE;
  270. }
  271. SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_STOP | DELETE);
  272. if (hService == NULL)
  273. {
  274. ::CloseServiceHandle(hSCM);
  275. MessageBox(NULL, _T("Couldn't open service"), m_szServiceName, MB_OK);
  276. return FALSE;
  277. }
  278. SERVICE_STATUS status;
  279. ::ControlService(hService, SERVICE_CONTROL_STOP, &status);
  280. BOOL bDelete = ::DeleteService(hService);
  281. ::CloseServiceHandle(hService);
  282. ::CloseServiceHandle(hSCM);
  283. if (bDelete)
  284. return TRUE;
  285. MessageBox(NULL, _T("Service could not be deleted"), m_szServiceName, MB_OK);
  286. return FALSE;
  287. }
  288. ///////////////////////////////////////////////////////////////////////////////////////
  289. // Logging functions
  290. int CServiceModule::LogEvent(WORD wType, int id, ...)
  291. {
  292. TCHAR chMsg[256];
  293. HANDLE hEventSource;
  294. LPTSTR lpszStrings[1];
  295. va_list pArg;
  296. va_start(pArg, id);
  297. _vsnprintf(chMsg, sizeof(chMsg), g_rgszLobbyEvents[id], pArg);
  298. va_end(pArg);
  299. lpszStrings[0] = chMsg;
  300. debugf("%s\n", lpszStrings[0]);
  301. if (m_bService)
  302. {
  303. /* Get a handle to use with ReportEvent(). */
  304. hEventSource = RegisterEventSource(NULL, m_szServiceName);
  305. if (hEventSource != NULL)
  306. {
  307. /* Write to event log. */
  308. ReportEvent(hEventSource, wType, 0, LobbyEventBaseID + id, NULL, 1, 0, (LPCTSTR*) &lpszStrings[0], NULL);
  309. DeregisterEventSource(hEventSource);
  310. }
  311. }
  312. else
  313. {
  314. // As we are not running as a service, just write the error to the console.
  315. _putts(chMsg);
  316. }
  317. return 0;
  318. }
  319. //////////////////////////////////////////////////////////////////////////////////////////////
  320. // Service startup and registration
  321. inline void CServiceModule::Start()
  322. {
  323. SERVICE_TABLE_ENTRY st[] =
  324. {
  325. { m_szServiceName, _ServiceMain },
  326. { NULL, NULL }
  327. };
  328. if (m_bService && !::StartServiceCtrlDispatcher(st))
  329. {
  330. m_bService = FALSE;
  331. }
  332. if (m_bService == FALSE)
  333. ExeMain();
  334. }
  335. inline void CServiceModule::ServiceMain(DWORD /* dwArgc */, LPTSTR* /* lpszArgv */)
  336. {
  337. // Register the control request handler
  338. m_status.dwCurrentState = SERVICE_START_PENDING;
  339. m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler);
  340. if (m_hServiceStatus == NULL)
  341. {
  342. LogEvent(EVENTLOG_ERROR_TYPE, LE_NoServiceHandler);
  343. return;
  344. }
  345. SetServiceStatus(SERVICE_START_PENDING);
  346. m_status.dwWin32ExitCode = S_OK;
  347. m_status.dwCheckPoint = 0;
  348. m_status.dwWaitHint = 0;
  349. // When the Run function returns, the service has stopped.
  350. Run();
  351. SetServiceStatus(SERVICE_STOPPED);
  352. LogEvent(EVENTLOG_INFORMATION_TYPE, LE_ServiceStopped);
  353. }
  354. void CServiceModule::ExeMain()
  355. {
  356. _putts("Running as an executable.");
  357. Run();
  358. }
  359. inline void CServiceModule::Handler(DWORD dwOpcode)
  360. {
  361. switch (dwOpcode)
  362. {
  363. case SERVICE_CONTROL_STOP:
  364. SetServiceStatus(SERVICE_STOP_PENDING);
  365. PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
  366. break;
  367. case SERVICE_CONTROL_PAUSE:
  368. break;
  369. case SERVICE_CONTROL_CONTINUE:
  370. break;
  371. case SERVICE_CONTROL_INTERROGATE:
  372. break;
  373. case SERVICE_CONTROL_SHUTDOWN:
  374. break;
  375. default:
  376. LogEvent(EVENTLOG_ERROR_TYPE, LE_BadServiceReq);
  377. }
  378. }
  379. void WINAPI CServiceModule::_ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
  380. {
  381. _Module.ServiceMain(dwArgc, lpszArgv);
  382. }
  383. void WINAPI CServiceModule::_Handler(DWORD dwOpcode)
  384. {
  385. _Module.Handler(dwOpcode);
  386. }
  387. void CServiceModule::SetServiceStatus(DWORD dwState)
  388. {
  389. m_status.dwCurrentState = dwState;
  390. ::SetServiceStatus(m_hServiceStatus, &m_status);
  391. }
  392. void CServiceModule::Run()
  393. {
  394. _Module.dwThreadID = GetCurrentThreadId();
  395. HRESULT hr = CoInitialize(NULL);
  396. // If you are running on NT 4.0 or higher you can use the following call
  397. // instead to make the EXE free threaded.
  398. // This means that calls come in on a random RPC thread
  399. // HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  400. _ASSERTE(SUCCEEDED(hr));
  401. // This provides a NULL DACL which will allow access to everyone.
  402. CSecurityDescriptor sd;
  403. sd.InitializeFromThreadToken();
  404. hr = CoInitializeSecurity(sd, -1, NULL, NULL,
  405. RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
  406. _ASSERTE(SUCCEEDED(hr));
  407. hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, REGCLS_MULTIPLEUSE);
  408. _ASSERTE(SUCCEEDED(hr));
  409. LogEvent(EVENTLOG_INFORMATION_TYPE, LE_Started);
  410. if (m_bService)
  411. SetServiceStatus(SERVICE_RUNNING);
  412. {
  413. TRef<CLobbyApp> plobbyapp = new CLobbyApp(this);
  414. if SUCCEEDED(plobbyapp->Init())
  415. plobbyapp->Run();
  416. else
  417. LogEvent(EVENTLOG_ERROR_TYPE, LE_StartFailed);
  418. }
  419. _Module.RevokeClassObjects();
  420. CoUninitialize();
  421. }
  422. /////////////////////////////////////////////////////////////////////////////
  423. //
  424. int __cdecl main(int argc, char *argv[])
  425. {
  426. HINSTANCE hInstance = GetModuleHandle(NULL);
  427. LPSTR lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
  428. // {5B5BE9E8-F1C7-4b95-960A-542A495CCE20}
  429. static const GUID LIBID_LOBBY =
  430. {0x5b5be9e8, 0xf1c7, 0x4b95, {0x96, 0xa, 0x54, 0x2a, 0x49, 0x5c, 0xce, 0x20}};
  431. _Module.Init(ObjectMap, hInstance, IDS_SERVICENAME, IDS_SERVICEDESC, &LIBID_LOBBY);
  432. _Module.m_bService = TRUE;
  433. if (argc > 1 && lstrcmpi(argv[1], _T("-UnregServer"))==0)
  434. return _Module.UnregisterServer();
  435. // Register as Local Server
  436. if (argc > 1 && lstrcmpi(argv[1], _T("-RegServer"))==0)
  437. return _Module.RegisterServer(FALSE, FALSE, NULL, NULL);
  438. // Register as Service
  439. if (argc > 1 && lstrcmpi(argv[1], _T("-Service"))==0)
  440. {
  441. if (argc == 4)
  442. return _Module.RegisterServer(FALSE, TRUE, argv[2], argv[3]);
  443. else
  444. return _Module.RegisterServer(FALSE, TRUE, NULL, NULL);
  445. }
  446. // Are we Service or Local Server
  447. CRegKey keyAppID;
  448. LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ);
  449. if (lRes != ERROR_SUCCESS)
  450. {
  451. _Module.LogEvent(EVENTLOG_ERROR_TYPE, LE_NoAppIDKey);
  452. return lRes;
  453. }
  454. CRegKey key;
  455. lRes = key.Open(keyAppID, _T("{EFD52202-45CB-454D-B477-33BC5C29BDF1}"), KEY_READ);
  456. if (lRes != ERROR_SUCCESS)
  457. {
  458. _Module.LogEvent(EVENTLOG_ERROR_TYPE, LE_NotRegistered);
  459. return lRes;
  460. }
  461. TCHAR szValue[_MAX_PATH];
  462. DWORD dwLen = _MAX_PATH;
  463. lRes = key.QueryValue(szValue, _T("LocalService"), &dwLen);
  464. _Module.m_bService = FALSE;
  465. if (lRes == ERROR_SUCCESS)
  466. _Module.m_bService = TRUE;
  467. _Module.Start();
  468. // When we get here, the service has been stopped
  469. return _Module.m_status.dwWin32ExitCode;
  470. }