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.

787 lines
19 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. Start.c
  5. Abstract:
  6. Process init and service controller interaction for dcomss.exe
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 06-14-95 Cloned from the old endpoint mapper.
  11. MazharM 10-12.98 Add pnp stuff
  12. TarunA 12-11-98 Removed pnpmngr.h
  13. a-sergiv 25-08-99 Defined gC2Security for process-wide use
  14. --*/
  15. //#define NCADG_MQ_ON
  16. #if !defined(_M_IA64)
  17. #define SPX_ON
  18. #endif
  19. //#define IPX_ON
  20. #if !defined(SPX_ON) && !defined(IPX_ON)
  21. #define SPX_IPX_OFF
  22. #endif
  23. #include <dcomss.h>
  24. #include <debnot.h>
  25. #include <olesem.hxx>
  26. #include <wtypes.h>
  27. #include <objbase.h>
  28. #include <winioctl.h>
  29. #include <ntddndis.h>
  30. #include <ndispnp.h>
  31. #include <dbt.h>
  32. #include <initguid.h>
  33. #include <ndisguid.h>
  34. #include <ndispnp.h>
  35. #ifndef SPX_IPX_OFF
  36. #include "sap.h"
  37. #endif
  38. #include "../../com/inc/secdes.hxx"
  39. extern LONG g_bInSCM; // from catalog
  40. C2Security gC2Security;
  41. // Array of service status blocks and pointers to service control
  42. // functions for each component service.
  43. #define SERVICE_NAME L"RPCSS"
  44. #define DEVICE_PREFIX L"\\\\.\\"
  45. VOID WINAPI ServiceMain(DWORD, PWSTR[]);
  46. extern BOOL CatalogDllMain (
  47. HINSTANCE hInst,
  48. DWORD dwReason,
  49. LPVOID lpReserved
  50. );
  51. void NotifyCOMOnSuspend();
  52. void NotifyCOMOnResume();
  53. extern DWORD gLockTlsIdx;
  54. SERVICE_TABLE_ENTRY gaServiceEntryTable[] = {
  55. { SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
  56. { NULL, NULL }
  57. };
  58. static SERVICE_STATUS gServiceStatus;
  59. static SERVICE_STATUS_HANDLE ghServiceHandle;
  60. #define OFFSET_TO_PTR(val, start) \
  61. (val) = ((val) == NULL) ? NULL : (PWCHAR) ( (PCHAR)(val) + (ULONG_PTR)(start))
  62. EXTERN_C const IID IID_IAssertConfig; // make the linker happy
  63. void
  64. CookupNodeId(PUCHAR NodeId)
  65. /*++
  66. Routine Description:
  67. This routine is called when all else fails. Here we mix a bunch of
  68. system parameters together for a 47bit node ID.
  69. Arguments:
  70. NodeId - Will be set to a value unlikly to be duplicated on another
  71. machine. It is not guaranteed to be unique even on this machine.
  72. But since UUIDs are (time + sequence) this is okay for
  73. a local UUID.
  74. It will be composed of:
  75. The computer name.
  76. The value of the performance counter.
  77. The system memory status.
  78. The total bytes and free bytes on C:
  79. The stack pointer (value).
  80. An LUID (locally unique ID)
  81. Plus whatever random stuff was in the NodeId to begin with.
  82. The NodeId returned is explicity made into a Multicast IEEE 802
  83. address so that it will not conflict with a 'real' IEEE 802
  84. based UUID.
  85. --*/
  86. {
  87. unsigned char LocalNodeId[6]; // NOT initialized.
  88. unsigned char ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  89. BOOL BoolResult;
  90. ULONG i = MAX_COMPUTERNAME_LENGTH+1;
  91. LARGE_INTEGER largeInt;
  92. LUID luid;
  93. ULONG UNALIGNED *NodeIdPart1 = (ULONG *)&LocalNodeId[0]; // Bytes 0 - 3
  94. ULONG UNALIGNED *NodeIdPart2 = (ULONG *)&LocalNodeId[2]; // Bytes 2 - 5
  95. MEMORYSTATUS memStatus;
  96. ULONG SectorsPerCluster;
  97. ULONG BytesPerSector;
  98. ULONG TotalClusters;
  99. ULONG FreeClusters;
  100. // Initialize the LocalNodeId. Seventeen is the most random, random number.
  101. memset(LocalNodeId, 17, sizeof(LocalNodeId));
  102. // The computer name is xor'ed in until it runs out.
  103. BoolResult =
  104. GetComputerNameA((CHAR *)ComputerName, &i);
  105. if (BoolResult)
  106. {
  107. unsigned char *p = ComputerName;
  108. i = 0;
  109. while(*p)
  110. {
  111. *( ((unsigned char *)LocalNodeId) + i) ^= *p++;
  112. if (++i > 6)
  113. {
  114. i = 0;
  115. }
  116. }
  117. }
  118. else
  119. {
  120. #if DBG
  121. DbgPrint ("GetComputerName failed - %d\n", GetLastError());
  122. #endif
  123. }
  124. // The performance counter is xor'ed into the LocalNodeId.
  125. BoolResult =
  126. QueryPerformanceCounter(&largeInt);
  127. if (BoolResult)
  128. {
  129. *NodeIdPart2 ^= largeInt.HighPart ^ largeInt.LowPart;
  130. *NodeIdPart1 ^= largeInt.HighPart ^ largeInt.LowPart;
  131. }
  132. else
  133. {
  134. #if DBG
  135. DbgPrint ("QueryPreformanceCount failed - %d\n", GetLastError());
  136. #endif
  137. }
  138. // The current SP is xor'ed into both parts of the LocalNodeId.
  139. *NodeIdPart1 ^= (ULONG_PTR)&LocalNodeId;
  140. *NodeIdPart2 ^= (ULONG_PTR)&LocalNodeId;
  141. // The memory status is Xor's into the LocalNodeId.
  142. memStatus.dwLength = sizeof(MEMORYSTATUS);
  143. GlobalMemoryStatus(&memStatus);
  144. *NodeIdPart1 ^= memStatus.dwMemoryLoad;
  145. *NodeIdPart2 ^= memStatus.dwTotalPhys;
  146. *NodeIdPart1 ^= memStatus.dwAvailPhys;
  147. *NodeIdPart1 ^= memStatus.dwTotalPageFile;
  148. *NodeIdPart2 ^= memStatus.dwAvailPageFile;
  149. *NodeIdPart2 ^= memStatus.dwTotalVirtual;
  150. *NodeIdPart1 ^= memStatus.dwAvailVirtual;
  151. // LUID's are good on this machine during this boot only.
  152. BoolResult =
  153. AllocateLocallyUniqueId(&luid);
  154. if (BoolResult)
  155. {
  156. *NodeIdPart1 ^= luid.LowPart;
  157. *NodeIdPart2 ^= luid.HighPart;
  158. }
  159. else
  160. {
  161. #if DBG
  162. DbgPrint ("Status %d\n", GetLastError());
  163. #endif
  164. }
  165. // Disk parameters and free space
  166. BoolResult =
  167. GetDiskFreeSpaceA("c:\\",
  168. &SectorsPerCluster,
  169. &BytesPerSector,
  170. &FreeClusters,
  171. &TotalClusters
  172. );
  173. if (BoolResult)
  174. {
  175. *NodeIdPart2 ^= TotalClusters * SectorsPerCluster * BytesPerSector;
  176. *NodeIdPart1 ^= FreeClusters * SectorsPerCluster * BytesPerSector;
  177. }
  178. else
  179. {
  180. #if DBG
  181. DbgPrint ("GetDiskFreeSpace failed - %d\n", GetLastError());
  182. #endif
  183. }
  184. // Or in the 'multicast' bit to distinguish this NodeId
  185. // from all other possible IEEE 802 addresses.
  186. LocalNodeId[0] |= 0x80;
  187. memcpy(NodeId, LocalNodeId, 6);
  188. }
  189. BOOLEAN
  190. getMacAddress (
  191. PUCHAR pMacAddress
  192. )
  193. /*++
  194. Function Name:getMacAddress
  195. Parameters:
  196. Description:
  197. Returns:
  198. --*/
  199. {
  200. int i;
  201. UINT fStatus;
  202. int Size = 1024*5;
  203. PNDIS_ENUM_INTF Interfaces;
  204. UCHAR OidVendData[16];
  205. Interfaces = (PNDIS_ENUM_INTF) I_RpcAllocate (Size);
  206. if (Interfaces == 0)
  207. {
  208. return FALSE;
  209. }
  210. if (NdisEnumerateInterfaces(Interfaces, Size))
  211. {
  212. UINT i;
  213. for (i = 0; i < Interfaces->TotalInterfaces; i++)
  214. {
  215. PUNICODE_STRING pDeviceName= &(Interfaces->Interface[i].DeviceName);
  216. UCHAR PermMacAddr[6];
  217. fStatus = NdisQueryHwAddress(pDeviceName, pMacAddress, PermMacAddr, &OidVendData[0]);
  218. if (fStatus && (OidVendData[0] != 0xFF
  219. || OidVendData[1] != 0xFF
  220. || OidVendData[2] != 0xFF))
  221. {
  222. I_RpcFree (Interfaces);
  223. return TRUE;
  224. }
  225. }
  226. }
  227. I_RpcFree (Interfaces);
  228. return FALSE;
  229. }
  230. extern "C" void
  231. DealWithDeviceEvent()
  232. /*++
  233. Function Name: DealWithDeviceEvent
  234. Parameters:
  235. Description:
  236. Returns:
  237. --*/
  238. {
  239. UCHAR MacAddress[8];
  240. NTSTATUS NtStatus;
  241. if (getMacAddress(&MacAddress[0]))
  242. {
  243. NtStatus = NtSetUuidSeed((PCHAR) &MacAddress[0]);
  244. }
  245. else
  246. {
  247. CookupNodeId(&MacAddress[0]);
  248. ASSERT(MacAddress[0] & 0x80);
  249. NtStatus = NtSetUuidSeed((PCHAR) &MacAddress[0]);
  250. }
  251. if (!NT_SUCCESS(NtStatus))
  252. {
  253. #if DBG
  254. DbgPrint("NtSetUuidSeed failed\n", NtStatus);
  255. #endif
  256. }
  257. #if !defined(SPX_IPX_OFF)
  258. UpdateSap( SAP_CTRL_UPDATE_ADDRESS );
  259. #endif
  260. }
  261. void
  262. DealWithPowerStatusEvent(DWORD dwEvent)
  263. {
  264. switch (dwEvent)
  265. {
  266. //
  267. // First the events we care about
  268. //
  269. case PBT_APMSUSPEND: // System is suspending operation.
  270. NotifyCOMOnSuspend();
  271. break;
  272. case PBT_APMRESUMESUSPEND: // Operation resuming after suspension.
  273. // This is the normal, user-initiated resume after a suspend.
  274. NotifyCOMOnResume();
  275. break;
  276. case PBT_APMRESUMEAUTOMATIC: // Operation resuming automatically after event.
  277. // For our purposes this is a regular resume, since we don't have any
  278. // direct dialogue with the user. Eg, wake-on-lan might cause this.
  279. NotifyCOMOnResume();
  280. break;
  281. case PBT_APMRESUMECRITICAL: // Operation resuming after critical suspension.
  282. // This means we're resuming w/o previously having had a suspend
  283. // notification. May have lost state (ie, ping set timers may have
  284. // rundown). Let's process the resume anyway, so that the ping set
  285. // timers start from scratch (might save somebody from a transient app
  286. // error).
  287. NotifyCOMOnResume();
  288. break;
  289. //
  290. // And then the ones we don't care about.
  291. //
  292. case PBT_APMBATTERYLOW: // Battery power is low.
  293. case PBT_APMOEMEVENT: // OEM-defined event occurred.
  294. case PBT_APMPOWERSTATUSCHANGE: // Power status has changed.
  295. case PBT_APMQUERYSUSPEND: // Request for permission to suspend.
  296. case PBT_APMQUERYSUSPENDFAILED: // Suspension request denied.
  297. break;
  298. default:
  299. ASSERT(!"Unexpected power event. Check to see if we should be dealing with it somehow.");
  300. break;
  301. }
  302. return;
  303. }
  304. ULONG WINAPI
  305. ServiceHandler(
  306. DWORD dwCode,
  307. DWORD dwEventType,
  308. PVOID EventData,
  309. PVOID pData
  310. )
  311. /*++
  312. Routine Description:
  313. Lowest level callback from the service controller to
  314. cause this service to change our status. (stop, start, pause, etc).
  315. Arguments:
  316. opCode - One of the service "Controls" value.
  317. SERVICE_CONTROL_{STOP, PAUSE, CONTINUE, INTERROGATE, SHUTDOWN}.
  318. Return Value:
  319. None
  320. --*/
  321. {
  322. switch(dwCode) {
  323. case SERVICE_CONTROL_STOP:
  324. case SERVICE_CONTROL_PAUSE:
  325. case SERVICE_CONTROL_CONTINUE:
  326. default:
  327. #if DBG
  328. DbgPrint("%S: Unexpected service control message %d.\n", SERVICE_NAME, dwCode);
  329. #endif
  330. ASSERT(0);
  331. break;
  332. case SERVICE_CONTROL_INTERROGATE:
  333. // Service controller wants us to call SetServiceStatus.
  334. UpdateState(gServiceStatus.dwCurrentState);
  335. break ;
  336. case SERVICE_CONTROL_SHUTDOWN:
  337. // The machine is shutting down. We'll be killed once we return.
  338. // Note, currently we don't register for these messages.
  339. break;
  340. case SERVICE_CONTROL_POWEREVENT:
  341. DealWithPowerStatusEvent(dwEventType);
  342. break;
  343. }
  344. return NO_ERROR;
  345. }
  346. VOID
  347. UpdateState(
  348. DWORD dwNewState
  349. )
  350. /*++
  351. Routine Description:
  352. Updates this services state with the service controller.
  353. Arguments:
  354. dwNewState - The next start for this service. One of
  355. SERVICE_START_PENDING
  356. SERVICE_RUNNING
  357. Return Value:
  358. None
  359. --*/
  360. {
  361. DWORD status = ERROR_SUCCESS;
  362. ASSERT( (dwNewState == SERVICE_RUNNING) ||
  363. (gServiceStatus.dwCurrentState != SERVICE_RUNNING) );
  364. switch (dwNewState)
  365. {
  366. case SERVICE_RUNNING:
  367. case SERVICE_STOPPED:
  368. gServiceStatus.dwCheckPoint = 0;
  369. gServiceStatus.dwWaitHint = 0;
  370. break;
  371. case SERVICE_START_PENDING:
  372. case SERVICE_STOP_PENDING:
  373. ++gServiceStatus.dwCheckPoint;
  374. gServiceStatus.dwWaitHint = 30000L;
  375. break;
  376. default:
  377. ASSERT(0);
  378. status = ERROR_INVALID_SERVICE_CONTROL;
  379. break;
  380. }
  381. if (status == ERROR_SUCCESS)
  382. {
  383. gServiceStatus.dwCurrentState = dwNewState;
  384. if (!SetServiceStatus(ghServiceHandle, &gServiceStatus))
  385. {
  386. status = GetLastError();
  387. }
  388. }
  389. #if DBG
  390. if (status != ERROR_SUCCESS)
  391. {
  392. DbgPrint("%S: Failed to update service state: %d\n", SERVICE_NAME, status);
  393. }
  394. #endif
  395. // We could return a status but how would we recover? Ignore it, the
  396. // worst thing is that services will kill us and there's nothing
  397. // we can about it if this call fails.
  398. return;
  399. }
  400. VOID WINAPI
  401. ServiceMain(
  402. DWORD argc,
  403. PWSTR argv[]
  404. )
  405. /*++
  406. Routine Description:
  407. Callback by the service controller when starting this service.
  408. Arguments:
  409. argc - number of arguments, usually 1
  410. argv - argv[0] is the name of the service.
  411. argv[>0] are arguments passed to the service.
  412. Return Value:
  413. None
  414. --*/
  415. {
  416. DWORD status = ERROR_SUCCESS;
  417. // COM needs power standby\resume events
  418. const DWORD RPCSS_CONTROLS = SERVICE_ACCEPT_POWEREVENT;
  419. // set the initial stack to 12K. This ensures enough commit
  420. // so that server threads don't need to extend their stacks
  421. RpcMgmtSetServerStackSize(3 * 4096);
  422. DealWithDeviceEvent();
  423. ASSERT( (argc >= 1 && lstrcmpiW(argv[0], SERVICE_NAME) == 0)
  424. || (argc == 0 && argv == 0));
  425. #if DBG==1
  426. // Note that we've completed running the static constructors
  427. ASSERT(g_fDllState == DLL_STATE_STATIC_CONSTRUCTING);
  428. g_fDllState = DLL_STATE_NORMAL;
  429. #endif
  430. // Initialize the mutex package
  431. status = RtlInitializeCriticalSection(&g_OleMutexCreationSem);
  432. if (!NT_SUCCESS(status))
  433. return;
  434. // Initialize TLS
  435. gLockTlsIdx = TlsAlloc();
  436. if (gLockTlsIdx == -1)
  437. {
  438. return;
  439. }
  440. // Initialize catalog
  441. CatalogDllMain (NULL, DLL_PROCESS_ATTACH, NULL);
  442. { // Create a named event for Vista to toggle event logging
  443. // Check to see if the event logging is installed and enabled
  444. //
  445. long cb = 128;
  446. char szValue[128];
  447. if (RegQueryValueA(HKEY_CLASSES_ROOT,
  448. "CLSID\\{6C736DB0-BD94-11D0-8A23-00AA00B58E10}\\EnableEvents",
  449. szValue, &cb) == ERROR_SUCCESS && !strcmp(szValue, "1"))
  450. {
  451. // [Sergei O. Ivanov (a-sergiv), 28-Jun-99]
  452. // This code here used to grant access to the whole world. But the world
  453. // tends to try and mess you up. So we'll only grant them limited access.
  454. SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  455. PSID pSidEveryone = NULL;
  456. PACL pAcl = NULL;
  457. DWORD cbAcl = 0;
  458. ACCESS_ALLOWED_ACE *pAce = NULL;
  459. AllocateAndInitializeSid(&SidAuthority, 1, SECURITY_WORLD_RID,
  460. 0, 0, 0, 0, 0, 0, 0, &pSidEveryone);
  461. if(pSidEveryone)
  462. {
  463. cbAcl = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(pSidEveryone);
  464. pAcl = (PACL) LocalAlloc(LMEM_FIXED, cbAcl);
  465. if(pAcl)
  466. {
  467. InitializeAcl(pAcl, cbAcl, ACL_REVISION);
  468. AddAccessAllowedAce(pAcl, ACL_REVISION, EVENT_QUERY_STATE|EVENT_MODIFY_STATE|SYNCHRONIZE|READ_CONTROL, pSidEveryone);
  469. }
  470. }
  471. // Create security descriptor and attach the DACL to it
  472. SECURITY_DESCRIPTOR sd;
  473. InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  474. SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE);
  475. SECURITY_ATTRIBUTES sa;
  476. sa.nLength = sizeof(sa);
  477. sa.bInheritHandle = FALSE;
  478. sa.lpSecurityDescriptor = &sd;
  479. // The toggle event, which is signaled by LEC and checked by all.
  480. // The handle never closes during the process
  481. HANDLE hLeak1 = CreateEventA(
  482. &sa, /* Security */
  483. TRUE, /* Manual reset */
  484. FALSE, /* InitialState is non-signaled */
  485. "MSFT.VSA.IEC.STATUS.6c736db0" /* Name */
  486. );
  487. if(pSidEveryone) FreeSid(pSidEveryone);
  488. if(pAcl) LocalFree(pAcl);
  489. }
  490. }
  491. // Tell catalog it's running in SCM
  492. g_bInSCM = TRUE;
  493. gServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  494. gServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  495. gServiceStatus.dwControlsAccepted = RPCSS_CONTROLS;
  496. gServiceStatus.dwWin32ExitCode = 0;
  497. gServiceStatus.dwServiceSpecificExitCode = 0;
  498. gServiceStatus.dwCheckPoint = 0;
  499. gServiceStatus.dwWaitHint = 3000L;
  500. ghServiceHandle = RegisterServiceCtrlHandlerEx(SERVICE_NAME,
  501. ServiceHandler,
  502. UIntToPtr(0xCAFECAFE) );
  503. if (0 == ghServiceHandle)
  504. {
  505. status = GetLastError();
  506. ASSERT(status != ERROR_SUCCESS);
  507. }
  508. if (status == ERROR_SUCCESS)
  509. {
  510. UpdateState(SERVICE_START_PENDING);
  511. }
  512. if (status == ERROR_SUCCESS)
  513. {
  514. // epts.c
  515. status = InitializeEndpointManager();
  516. }
  517. #ifndef _CHICAGO_
  518. // Start Ep Mapper.
  519. if (status == ERROR_SUCCESS)
  520. {
  521. // ..\epmap\server.c
  522. UpdateState(SERVICE_START_PENDING);
  523. status = StartEndpointMapper();
  524. }
  525. #ifdef NCADG_MQ_ON
  526. // Start MQ Manager Interface
  527. if (status == ERROR_SUCCESS)
  528. {
  529. UpdateState(SERVICE_START_PENDING);
  530. status = StartMqManagement();
  531. }
  532. #endif // NCADG_MQ_ON
  533. #endif
  534. // Do pre-listen olescm initialization
  535. if (status == ERROR_SUCCESS)
  536. {
  537. UpdateState(SERVICE_START_PENDING);
  538. status = InitializeSCMBeforeListen();
  539. }
  540. // Start object resolver
  541. if (status == ERROR_SUCCESS)
  542. {
  543. // ..\objex\objex.cxx
  544. UpdateState(SERVICE_START_PENDING);
  545. status = StartObjectExporter();
  546. }
  547. // Start OLESCM
  548. if (status == ERROR_SUCCESS)
  549. {
  550. UpdateState(SERVICE_START_PENDING);
  551. status = InitializeSCM();
  552. }
  553. // Start listening for RPC requests
  554. if (status == ERROR_SUCCESS)
  555. {
  556. status = RpcServerListen(1, 1234, TRUE);
  557. if (status == RPC_S_OK)
  558. {
  559. while (RpcMgmtIsServerListening(0) == RPC_S_NOT_LISTENING)
  560. {
  561. Sleep(100);
  562. }
  563. }
  564. }
  565. //
  566. // There is some initialization that must be done after we
  567. // have done the RpcServerListen.
  568. //
  569. if (status == ERROR_SUCCESS)
  570. {
  571. // ..\olescm\scmsvc.cxx
  572. UpdateState(SERVICE_START_PENDING);
  573. InitializeSCMAfterListen();
  574. }
  575. // Trim our working set - free space now at the cost of time later.
  576. if (status == ERROR_SUCCESS)
  577. {
  578. UpdateState(SERVICE_RUNNING);
  579. }
  580. #ifdef DEBUGRPC
  581. if (status != ERROR_SUCCESS)
  582. {
  583. DbgPrint("RPCSS ServiceMain failed %d (%08x)\n", status, status);
  584. }
  585. #endif
  586. if (status == ERROR_SUCCESS)
  587. {
  588. ObjectExporterWorkerThread(0);
  589. ASSERT(0);
  590. }
  591. return;
  592. }
  593. extern HRESULT PrivGetRPCSSInfo(REFCLSID rclsid, REFIID riid, void** pIntf);
  594. extern "C"
  595. {
  596. STDAPI GetRPCSSInfo(REFCLSID rclsid, REFIID riid, void** ppv)
  597. {
  598. return PrivGetRPCSSInfo(rclsid, riid, ppv);
  599. };
  600. STDAPI GetCatalogHelper(REFIID riid, void** ppv);
  601. STDAPI CoGetComCatalog(REFIID riid, void** ppv)
  602. {
  603. return GetCatalogHelper (riid, ppv);
  604. }
  605. }