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.

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