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.

451 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997-2001.
  5. //
  6. // File: S V C M A I N . C P P
  7. //
  8. // Contents: Service main for netman.dll
  9. //
  10. // Notes:
  11. //
  12. // Author: shaunco 3 Apr 1998
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <dbt.h>
  18. #include "nmbase.h"
  19. #include "nminit.h"
  20. #include "nmres.h"
  21. #include "cmevent.h"
  22. #include "eventq.h"
  23. #include "wsdpsvc.h"
  24. // Includes for COM objects needed in the following object map.
  25. //
  26. // Connection Manager
  27. //
  28. #include "..\conman\conman.h"
  29. #include "..\conman\conman2.h"
  30. #include "..\conman\enum.h"
  31. // As the object map needs to map directly to the original class manager, we'll have to define
  32. // NO_CM_SEPERATE_NAMESPACES so that the code doesn't put the class managers in a seperate namespace.
  33. // Take this out from time to time and compile without it. All the code has to compile fine.
  34. // However, it won't link.
  35. #define NO_CM_SEPERATE_NAMESPACES
  36. #include "cmdirect.h"
  37. // Install queue
  38. //
  39. #include "ncqueue.h"
  40. // Home networking support
  41. //
  42. #include "nmhnet.h"
  43. // NetGroupPolicies
  44. #include "nmpolicy.h"
  45. #define INITGUID
  46. DEFINE_GUID(CLSID_InternetConnectionBeaconService,0x04df613a,0x5610,0x11d4,0x9e,0xc8,0x00,0xb0,0xd0,0x22,0xdd,0x1f);
  47. // TODO Remove this when we have proper idl
  48. CServiceModule _Module;
  49. BEGIN_OBJECT_MAP(ObjectMap)
  50. // Connection Manager
  51. //
  52. OBJECT_ENTRY(CLSID_ConnectionManager, CConnectionManager)
  53. OBJECT_ENTRY(CLSID_ConnectionManagerEnumConnection, CConnectionManagerEnumConnection)
  54. // Connection Manager2
  55. OBJECT_ENTRY(CLSID_ConnectionManager2, CConnectionManager2)
  56. // Connection Class Managers
  57. //
  58. OBJECT_ENTRY(CLSID_InboundConnectionManager, CMDIRECT(INBOUND, CInboundConnectionManager))
  59. OBJECT_ENTRY(CLSID_InboundConnectionManagerEnumConnection, CMDIRECT(INBOUND, CInboundConnectionManagerEnumConnection))
  60. OBJECT_ENTRY(CLSID_LanConnectionManager, CMDIRECT(LANCON, CLanConnectionManager))
  61. OBJECT_ENTRY(CLSID_LanConnectionManagerEnumConnection, CMDIRECT(LANCON, CLanConnectionManagerEnumConnection))
  62. OBJECT_ENTRY(CLSID_WanConnectionManager, CMDIRECT(DIALUP, CWanConnectionManager))
  63. OBJECT_ENTRY(CLSID_WanConnectionManagerEnumConnection, CMDIRECT(DIALUP, CWanConnectionManagerEnumConnection))
  64. OBJECT_ENTRY(CLSID_SharedAccessConnectionManager, CMDIRECT(SHAREDACCESS, CSharedAccessConnectionManager))
  65. OBJECT_ENTRY(CLSID_SharedAccessConnectionManagerEnumConnection, CMDIRECT(SHAREDACCESS, CSharedAccessConnectionManagerEnumConnection))
  66. // Connection Objects
  67. //
  68. OBJECT_ENTRY(CLSID_DialupConnection, CMDIRECT(DIALUP, CDialupConnection))
  69. OBJECT_ENTRY(CLSID_InboundConnection, CMDIRECT(INBOUND, CInboundConnection))
  70. OBJECT_ENTRY(CLSID_LanConnection, CMDIRECT(LANCON, CLanConnection))
  71. OBJECT_ENTRY(CLSID_SharedAccessConnection, CMDIRECT(SHAREDACCESS, CSharedAccessConnection))
  72. // Install queue
  73. //
  74. OBJECT_ENTRY(CLSID_InstallQueue, CInstallQueue)
  75. // Home networking support
  76. //
  77. OBJECT_ENTRY(CLSID_NetConnectionHNetUtil, CNetConnectionHNetUtil)
  78. // NetGroupPolicies
  79. OBJECT_ENTRY(CLSID_NetGroupPolicies, CNetMachinePolicies)
  80. END_OBJECT_MAP()
  81. VOID
  82. CServiceModule::DllProcessAttach (
  83. IN HINSTANCE hinst) throw()
  84. {
  85. CComModule::Init (ObjectMap, hinst);
  86. }
  87. VOID
  88. CServiceModule::DllProcessDetach (
  89. IN VOID) throw()
  90. {
  91. CComModule::Term ();
  92. }
  93. DWORD
  94. CServiceModule::DwHandler (
  95. IN DWORD dwControl,
  96. IN DWORD dwEventType,
  97. IN LPCVOID pEventData,
  98. IN LPCVOID pContext)
  99. {
  100. if (SERVICE_CONTROL_STOP == dwControl)
  101. {
  102. HRESULT hr;
  103. TraceTag (ttidConman, "Received SERVICE_CONTROL_STOP request");
  104. SetServiceStatus (SERVICE_STOP_PENDING);
  105. hr = ServiceShutdown();
  106. }
  107. else if (SERVICE_CONTROL_INTERROGATE == dwControl)
  108. {
  109. TraceTag (ttidConman, "Received SERVICE_CONTROL_INTERROGATE request");
  110. UpdateServiceStatus (FALSE);
  111. }
  112. else if (SERVICE_CONTROL_SESSIONCHANGE == dwControl)
  113. {
  114. TraceTag (ttidConman, "Received SERVICE_CONTROL_SESSIONCHANGE request");
  115. CONMAN_EVENT* pEvent = new CONMAN_EVENT;
  116. // Send out a CONNECTION_DELETED event for a non-existing connection (GUID_NULL).
  117. // This will cause us to send an event to every logged in user on the system.
  118. // The event won't do anything, however, it will allow us to verify
  119. // each of the connection points to see if they are still alive.
  120. // Otherwise we could queue the connection points up every time a
  121. // user logs in & out again if no other networks events are being fired,
  122. // causing us to overflow RPC.
  123. //
  124. // See: NTRAID9:490981. rpcrt4!FindOrCreateLrpcAssociation has ~40,000 client LRPC associations for various COM endpoints
  125. if (pEvent)
  126. {
  127. ZeroMemory(pEvent, sizeof(CONMAN_EVENT));
  128. pEvent->guidId = GUID_NULL;
  129. pEvent->Type = CONNECTION_DELETED;
  130. if (!QueueUserWorkItemInThread(ConmanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  131. {
  132. FreeConmanEvent(pEvent);
  133. }
  134. }
  135. }
  136. else if ((SERVICE_CONTROL_DEVICEEVENT == dwControl) && pEventData)
  137. {
  138. DEV_BROADCAST_DEVICEINTERFACE* pInfo =
  139. (DEV_BROADCAST_DEVICEINTERFACE*)pEventData;
  140. if (DBT_DEVTYP_DEVICEINTERFACE == pInfo->dbcc_devicetype)
  141. {
  142. if (DBT_DEVICEARRIVAL == dwEventType)
  143. {
  144. TraceTag (ttidConman, "Device arrival: [%S]",
  145. pInfo->dbcc_name);
  146. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  147. }
  148. else if (DBT_DEVICEREMOVECOMPLETE == dwEventType)
  149. {
  150. GUID guidAdapter = GUID_NULL;
  151. WCHAR szGuid[MAX_PATH];
  152. WCHAR szTempName[MAX_PATH];
  153. WCHAR* szFindGuid;
  154. TraceTag (ttidConman, "Device removed: [%S]",
  155. pInfo->dbcc_name);
  156. szFindGuid = wcsrchr(pInfo->dbcc_name, L'{');
  157. if (szFindGuid)
  158. {
  159. wcscpy(szGuid, szFindGuid);
  160. IIDFromString(szGuid, &guidAdapter);
  161. }
  162. if (!IsEqualGUID(guidAdapter, GUID_NULL))
  163. {
  164. CONMAN_EVENT* pEvent;
  165. pEvent = new CONMAN_EVENT;
  166. if (pEvent)
  167. {
  168. pEvent->ConnectionManager = CONMAN_LAN;
  169. pEvent->guidId = guidAdapter;
  170. pEvent->Type = CONNECTION_STATUS_CHANGE;
  171. pEvent->Status = NCS_DISCONNECTED;
  172. if (!QueueUserWorkItemInThread(LanEventWorkItem, pEvent, EVENTMGR_CONMAN))
  173. {
  174. FreeConmanEvent(pEvent);
  175. }
  176. }
  177. }
  178. else
  179. {
  180. LanEventNotify (REFRESH_ALL, NULL, NULL, NULL);
  181. }
  182. }
  183. }
  184. }
  185. return 1;
  186. }
  187. VOID
  188. CServiceModule::SetServiceStatus(DWORD dwState) throw()
  189. {
  190. m_status.dwCurrentState = dwState;
  191. m_status.dwCheckPoint = 0;
  192. if (!::SetServiceStatus (m_hStatus, &m_status))
  193. {
  194. TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
  195. "CServiceModule::SetServiceStatus");
  196. }
  197. }
  198. VOID CServiceModule::UpdateServiceStatus (
  199. BOOL fUpdateCheckpoint /* = TRUE */) throw()
  200. {
  201. if (fUpdateCheckpoint)
  202. {
  203. m_status.dwCheckPoint++;
  204. }
  205. if (!::SetServiceStatus (m_hStatus, &m_status))
  206. {
  207. TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
  208. "CServiceModule::UpdateServiceStatus");
  209. }
  210. }
  211. VOID
  212. CServiceModule::Run() throw()
  213. {
  214. HRESULT hr = CoInitializeEx (NULL,
  215. COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
  216. TraceHr (ttidError, FAL, hr, FALSE, "CServiceModule::Run: "
  217. "CoInitializeEx failed");
  218. if (SUCCEEDED(hr))
  219. {
  220. TraceTag (ttidConman, "Calling RegisterClassObjects...");
  221. // Create the event to sychronize registering our class objects
  222. // with the connection manager which attempts to CoCreate
  223. // objects which are also registered here. I've seen cases
  224. // where the connection manager will be off and running before
  225. // this completes causing CoCreateInstance to fail.
  226. // The connection manager will wait on this event before
  227. // executing CoCreateInstance.
  228. //
  229. HANDLE hEvent;
  230. hr = HrNmCreateClassObjectRegistrationEvent (&hEvent);
  231. if (SUCCEEDED(hr))
  232. {
  233. hr = _Module.RegisterClassObjects (
  234. CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
  235. REGCLS_MULTIPLEUSE);
  236. TraceHr (ttidError, FAL, hr, FALSE, "CServiceModule::Run: "
  237. "_Module.RegisterClassObjects failed");
  238. // Signal the event and close it. If this delete's the
  239. // event, so be it. It's purpose is served as all
  240. // class objects have been registered.
  241. //
  242. SetEvent (hEvent);
  243. CloseHandle (hEvent);
  244. }
  245. if (SUCCEEDED(hr))
  246. {
  247. hr = ServiceStartup();
  248. }
  249. CoUninitialize();
  250. }
  251. }
  252. VOID
  253. CServiceModule::ServiceMain (
  254. IN DWORD argc,
  255. IN LPCWSTR argv[]) throw()
  256. {
  257. // Reset the version era for RAS phonebook entry modifications.
  258. //
  259. g_lRasEntryModifiedVersionEra = 0;
  260. m_fRasmanReferenced = FALSE;
  261. m_dwThreadID = GetCurrentThreadId ();
  262. ZeroMemory (&m_status, sizeof(m_status));
  263. m_status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  264. m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SESSIONCHANGE;
  265. // Register the service control handler.
  266. //
  267. m_hStatus = RegisterServiceCtrlHandlerEx (
  268. L"netman",
  269. _DwHandler,
  270. NULL);
  271. if (m_hStatus)
  272. {
  273. SetServiceStatus (SERVICE_START_PENDING);
  274. // When the Run function returns, the service is running.
  275. // We now handle shutdown from ServiceShutdown when our DwHandler
  276. // is called and is passed SERVICE_CONTROL_STOP as the dwControl
  277. // parameter. This allows us to terminate our message pump thread
  278. // which effectively reduces us to 0 threads that we own.
  279. Run ();
  280. }
  281. else
  282. {
  283. TraceHr (ttidError, FAL, HrFromLastWin32Error(), FALSE,
  284. "CServiceModule::ServiceMain - RegisterServiceCtrlHandler failed");
  285. }
  286. }
  287. // static
  288. DWORD
  289. WINAPI
  290. CServiceModule::_DwHandler (
  291. IN DWORD dwControl,
  292. IN DWORD dwEventType,
  293. IN WACKYAPI LPVOID pEventData,
  294. IN WACKYAPI LPVOID pContext)
  295. {
  296. return _Module.DwHandler (dwControl, dwEventType, const_cast<LPCVOID>(pEventData), const_cast<LPCVOID>(pContext));
  297. }
  298. VOID
  299. CServiceModule::ReferenceRasman (
  300. IN RASREFTYPE RefType) throw()
  301. {
  302. BOOL fRef = (REF_REFERENCE == RefType);
  303. if (REF_INITIALIZE == RefType)
  304. {
  305. Assert (!fRef);
  306. // RasInitialize implicitly references rasman.
  307. //
  308. RasInitialize ();
  309. }
  310. // If we need to reference and we're not already,
  311. // or we need unreference and we're referenced, do the appropriate thing.
  312. // (This is logical xor. Quite different than bitwise xor when
  313. // the two arguments don't neccesarily have the same value for TRUE.)
  314. //
  315. else if ((fRef && !m_fRasmanReferenced) ||
  316. (!fRef && m_fRasmanReferenced))
  317. {
  318. RasReferenceRasman (fRef);
  319. m_fRasmanReferenced = fRef;
  320. }
  321. }
  322. HRESULT CServiceModule::ServiceStartup()
  323. {
  324. HRESULT hr = S_OK;
  325. StartWsdpService (); // Starts WSDP service on DTC/AdvServer build/
  326. // no-op otherwise
  327. InitializeHNetSupport();
  328. SetServiceStatus (SERVICE_RUNNING);
  329. TraceTag (ttidConman, "Netman is now running...");
  330. return hr;
  331. }
  332. HRESULT CServiceModule::ServiceShutdown()
  333. {
  334. HRESULT hr = S_OK;
  335. TraceFileFunc(ttidConman);
  336. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  337. if (SUCCEEDED(hr))
  338. {
  339. TraceTag(ttidConman, "ServiceShutdown: UninitializeEventHandler");
  340. hr = UninitializeEventHandler();
  341. if (SUCCEEDED(hr))
  342. {
  343. TraceTag(ttidConman, "ServiceShutdown: CleanupHNetSupport");
  344. CleanupHNetSupport();
  345. TraceTag(ttidConman, "ServiceShutdown: StopWsdpService");
  346. StopWsdpService (); // Stops WSDP service if necessary
  347. // We must synchronize with the install queue's thread otherwise
  348. // RevokeClassObjects will kill the InstallQueue object and
  349. // CoUninitialize will free the NetCfg module before the thread
  350. // is finished.
  351. //
  352. TraceTag(ttidConman, "ServiceShutdown: WaitForInstallQueueToExit");
  353. WaitForInstallQueueToExit();
  354. TraceTag(ttidConman, "ServiceShutdown: RevokeClassObjects");
  355. _Module.RevokeClassObjects ();
  356. // Unreference rasman now that our service is about to stop.
  357. //
  358. TraceTag(ttidConman, "ServiceShutdown: ReferenceRasman");
  359. _Module.ReferenceRasman (REF_UNREFERENCE);
  360. AssertIfAnyAllocatedObjects();
  361. SetServiceStatus(SERVICE_STOPPED);
  362. }
  363. CoUninitialize();
  364. TraceTag(ttidConman, "ServiceShutdown: Completed");
  365. }
  366. if (FAILED(hr))
  367. {
  368. SetServiceStatus(SERVICE_RUNNING);
  369. }
  370. return hr;
  371. }