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.

1484 lines
34 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. main.c
  5. Abstract:
  6. This is the main routine for the Internet Services suite.
  7. Author:
  8. David Treadwell (davidtr) 7-27-93
  9. Revision History:
  10. Murali Krishnan ( Muralik) 16-Nov-1994 Added Gopher service
  11. Murali Krishnan ( Muralik) 3-July-1995 Removed non-internet info + trims
  12. Sophia Chung (sophiac) 09-Oct-1995 Splitted internet services into
  13. access and info services
  14. Murali Krishnan ( Muralik) 20-Feb-1996 Enabled to run on NT Workstation
  15. Emily Kruglick ( EmilyK) 14-Jun-2000 Moved file from iis 5 tree to iis 6.
  16. Removed all Win95 support.
  17. Added support for WAS controlling W3SVC.
  18. --*/
  19. //
  20. // INCLUDES
  21. //
  22. #include <nt.h>
  23. #include <ntrtl.h>
  24. #include <nturtl.h>
  25. #include <windows.h>
  26. #include <winsvc.h> // Service control APIs
  27. #include <rpc.h>
  28. #include <stdlib.h>
  29. #include <inetsvcs.h>
  30. #include <iis64.h>
  31. #include "waslaunch.hxx"
  32. #include "inetimsg.h"
  33. #include "iisadmin.hxx"
  34. #include <objbase.h>
  35. #include "regconst.h"
  36. //
  37. // Modifications to this name should also be made in tsunami.hxx
  38. //
  39. #define INETA_W3ONLY_NO_AUTH TEXT("W3OnlyNoAuth")
  40. //
  41. // Functions used to start/stop the RPC server
  42. //
  43. typedef DWORD ( *PFN_INETINFO_START_RPC_SERVER) ( VOID );
  44. typedef DWORD ( *PFN_INETINFO_STOP_RPC_SERVER) ( VOID );
  45. //
  46. // Local function used by the above to load and invoke a service DLL.
  47. //
  48. VOID
  49. InetinfoStartService (
  50. IN DWORD argc,
  51. IN LPSTR argv[]
  52. );
  53. VOID
  54. StartDispatchTable(
  55. VOID
  56. );
  57. //
  58. // Functions used to preload dlls into the inetinfo process
  59. //
  60. BOOL
  61. LoadPreloadDlls(
  62. HMODULE * * ppPreloadDllHandles
  63. );
  64. VOID
  65. UnloadPreloadDlls(
  66. HMODULE * * ppPreloadDllHandles
  67. );
  68. //
  69. // Used if the services Dll or entry point can't be found
  70. //
  71. VOID
  72. AbortService(
  73. LPSTR ServiceName,
  74. DWORD Error
  75. );
  76. //
  77. // Dispatch table for all services. Passed to NetServiceStartCtrlDispatcher.
  78. //
  79. // Add new service entries here and in the DLL name list.
  80. // Also add an entry in the following table InetServiceDllTable
  81. //
  82. SERVICE_TABLE_ENTRY InetServiceDispatchTable[] = {
  83. { "GopherSvc", InetinfoStartService },
  84. { "MSFtpSvc", InetinfoStartService },
  85. { "W3Svc", InetinfoStartService },
  86. { "IISADMIN", InetinfoStartService },
  87. { NULL, NULL },
  88. };
  89. SERVICE_TABLE_ENTRY W3ServiceDispatchTable[] = {
  90. { "W3Svc", InetinfoStartService },
  91. { NULL, NULL },
  92. };
  93. //
  94. // DLL names for all services.
  95. // (should correspond exactly with above InetServiceDispatchTable)
  96. //
  97. struct SERVICE_DLL_TABLE_ENTRY {
  98. LPSTR lpServiceName;
  99. LPSTR lpDllName;
  100. CRITICAL_SECTION csLoadLock;
  101. } InetServiceDllTable[] = {
  102. { "GopherSvc", "gopherd.dll" },
  103. { "MSFtpSvc", "ftpsvc2.dll" },
  104. { "W3Svc", "w3svc.dll" },
  105. { "IISADMIN", "iisadmin.dll" },
  106. { NULL, NULL }
  107. };
  108. //
  109. // Global parameter data passed to each service.
  110. //
  111. TCPSVCS_GLOBAL_DATA InetinfoGlobalData;
  112. #include <initguid.h>
  113. DEFINE_GUID(IisExeGuid,
  114. 0x784d8901, 0xaa8c, 0x11d2, 0x92, 0x5e, 0x00, 0xc0, 0x4f, 0x72, 0xd9, 0x0e);
  115. #ifndef _NO_TRACING_
  116. #include "dbgutil.h"
  117. #include "pudebug.h"
  118. DECLARE_DEBUG_PRINTS_OBJECT()
  119. #endif
  120. //
  121. // A global variable that remembers that we'll refuse to start.
  122. //
  123. BOOL RefuseStartup = FALSE;
  124. BOOL g_fRunAsExe = FALSE;
  125. BOOL g_fW3svcNoAuth = FALSE;
  126. BOOL g_fOleInitialized = TRUE;
  127. DWORD __cdecl
  128. main(
  129. IN DWORD argc,
  130. IN LPSTR argv[]
  131. )
  132. /*++
  133. Routine Description:
  134. This is the main routine for the LANMan services. It starts up the
  135. main thread that is going to handle the control requests from the
  136. service controller.
  137. It basically sets up the ControlDispatcher and, on return, exits
  138. from this main thread. The call to NetServiceStartCtrlDispatcher
  139. does not return until all services have terminated, and this process
  140. can go away.
  141. The ControlDispatcher thread will start/stop/pause/continue any
  142. services. If a service is to be started, it will create a thread
  143. and then call the main routine of that service. The "main routine"
  144. for each service is actually an intermediate function implemented in
  145. this module that loads the DLL containing the server being started
  146. and calls its entry point.
  147. Arguments:
  148. None.
  149. Return Value:
  150. None.
  151. --*/
  152. {
  153. HMODULE dllHandle = NULL;
  154. HINSTANCE hRpcRef = NULL;
  155. HMODULE * pPreloadDllHandles = NULL;
  156. DWORD dwIndex;
  157. struct SERVICE_DLL_TABLE_ENTRY * pEntry;
  158. DWORD err = ERROR_SUCCESS;
  159. //
  160. // Initialize OLE
  161. //
  162. #ifndef _NO_TRACING_
  163. HRESULT hr;
  164. CREATE_DEBUG_PRINT_OBJECT("Inetinfo.exe");
  165. // CREATE_INITIALIZE_DEBUG();
  166. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED );
  167. #else
  168. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED );
  169. #endif
  170. if ( FAILED(hr)) {
  171. if ( hr != E_INVALIDARG ) {
  172. IIS_PRINTF((buff,"CoInitialize failed with %x\n",hr));
  173. g_fOleInitialized = FALSE;
  174. }
  175. }
  176. //
  177. // Initialize Global Data.
  178. //
  179. //
  180. // Use the rpcref library, so that multiple services can
  181. // independently "start" the rpc server
  182. //
  183. hRpcRef = LoadLibrary("rpcref.dll");
  184. if ( hRpcRef != NULL )
  185. {
  186. InetinfoGlobalData.StartRpcServerListen =
  187. (PFN_INETINFO_START_RPC_SERVER)
  188. GetProcAddress(hRpcRef,"InetinfoStartRpcServerListen");
  189. InetinfoGlobalData.StopRpcServerListen =
  190. (PFN_INETINFO_STOP_RPC_SERVER)
  191. GetProcAddress(hRpcRef,"InetinfoStopRpcServerListen");
  192. }
  193. else
  194. {
  195. IIS_PRINTF((buff,
  196. "Error %d loading rpcref.dll\n",
  197. GetLastError() ));
  198. #ifndef _NO_TRACING_
  199. DELETE_DEBUG_PRINT_OBJECT();
  200. // DELETE_INITIALIZE_DEBUG()
  201. #endif
  202. return GetLastError();
  203. }
  204. //
  205. // Initialize service entry locks
  206. //
  207. for ( dwIndex = 0 ; ; dwIndex++ )
  208. {
  209. pEntry = &( InetServiceDllTable[ dwIndex ] );
  210. if ( pEntry->lpServiceName == NULL )
  211. {
  212. break;
  213. }
  214. InitializeCriticalSection( &( pEntry->csLoadLock ) );
  215. }
  216. //
  217. // Disable hard-error popups.
  218. //
  219. SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX );
  220. //
  221. // Preload Dlls specified in the registry
  222. //
  223. if ( !LoadPreloadDlls( &pPreloadDllHandles ) )
  224. {
  225. IIS_PRINTF(( buff, "Error pre-loading DLLs\n" ));
  226. }
  227. if ( (argc > 2) && !_stricmp( argv[1], "-e" ))
  228. {
  229. PCHAR pszName = argv[2];
  230. HANDLE hAsExeEvent;
  231. HANDLE hStartW3svc = NULL;
  232. PIISADMIN_SERVICE_DLL_EXEENTRY IisAdminExeEntry = NULL;
  233. PIISADMIN_SERVICE_DLL_EXEEXIT IisAdminExeExit = NULL;
  234. BOOL IsIisAdmin = TRUE;
  235. //
  236. // Create a named event. The common internet services code attempts
  237. // to create a semaphore with the same name, if it fails then the
  238. // service is being run as an exe
  239. //
  240. g_fRunAsExe = TRUE;
  241. hAsExeEvent = CreateEvent( NULL,
  242. FALSE,
  243. FALSE,
  244. IIS_AS_EXE_OBJECT_NAME);
  245. err = GetLastError();
  246. if ( hAsExeEvent == NULL ) {
  247. IIS_PRINTF((buff,"Cannot create %s event. err %d\n",
  248. IIS_AS_EXE_OBJECT_NAME, err));
  249. goto Finished;
  250. }
  251. if ( err != ERROR_SUCCESS ) {
  252. CloseHandle(hAsExeEvent);
  253. IIS_PRINTF((buff,
  254. "Error %d in CreateEvent[%s]\n",
  255. err, IIS_AS_EXE_OBJECT_NAME));
  256. goto Finished;
  257. }
  258. //
  259. // All services are dependent on IISADMIN
  260. // so if it's not IISADMIN call it
  261. //
  262. if ( (_stricmp(IISADMIN_NAME, pszName) != 0) ) {
  263. //
  264. // Not IISADMIN
  265. //
  266. IsIisAdmin = FALSE;
  267. dllHandle = LoadLibrary(IISADMIN_NAME);
  268. if ( dllHandle == NULL ) {
  269. err = GetLastError();
  270. IIS_PRINTF((buff,
  271. "Inetinfo: Failed to load DLL %s: %ld\n",
  272. IISADMIN_NAME, err));
  273. goto Finished;
  274. }
  275. //
  276. // Get the address of the service's main entry point. This
  277. // entry point has a well-known name.
  278. //
  279. IisAdminExeEntry = (PIISADMIN_SERVICE_DLL_EXEENTRY)GetProcAddress(
  280. dllHandle,
  281. IISADMIN_EXEENTRY_STRING
  282. );
  283. if (IisAdminExeEntry == NULL ) {
  284. err = GetLastError();
  285. IIS_PRINTF((buff,
  286. "Inetinfo: Can't find entry %s in DLL %s: %ld\n",
  287. IISADMIN_EXEENTRY_STRING, IISADMIN_NAME, err));
  288. goto Finished;
  289. }
  290. IisAdminExeExit = (PIISADMIN_SERVICE_DLL_EXEEXIT)GetProcAddress(
  291. dllHandle,
  292. IISADMIN_EXEEXIT_STRING
  293. );
  294. if (IisAdminExeExit == NULL ) {
  295. err = GetLastError();
  296. IIS_PRINTF((buff,
  297. "Inetinfo: Can't find entry %s in DLL %s: %ld\n",
  298. IISADMIN_EXEEXIT_STRING, IISADMIN_NAME, err);
  299. );
  300. goto Finished;
  301. }
  302. if (!IisAdminExeEntry( TRUE, FALSE, TRUE)) {
  303. IIS_PRINTF((buff,"IISadmin init failed\n"));
  304. err = 1;
  305. goto Finished;
  306. }
  307. }
  308. //
  309. // Offset argv so that the first entry points to the dll name to
  310. // load
  311. //
  312. IIS_PRINTF((buff,"Starting %s\n", pszName));
  313. InetinfoStartService( 1, &argv[2] );
  314. if (!IsIisAdmin) {
  315. IisAdminExeExit();
  316. }
  317. if ( hStartW3svc != NULL ) {
  318. CloseHandle( hStartW3svc );
  319. }
  320. CloseHandle( hAsExeEvent );
  321. } else {
  322. StartDispatchTable( );
  323. }
  324. DBGPRINTF((
  325. DBG_CONTEXT,
  326. "Finishing main CTC = %d \n",
  327. GetTickCount()
  328. ));
  329. Finished:
  330. //
  331. // Unload pre-loaded Dlls
  332. //
  333. UnloadPreloadDlls( &pPreloadDllHandles );
  334. //
  335. // Cleanup OLE
  336. //
  337. if ( g_fOleInitialized ) {
  338. CoUninitialize();
  339. g_fOleInitialized = FALSE;
  340. }
  341. //
  342. // Free the admin service dll
  343. // Note: this must happen after CoUninitialize or it causes
  344. // a crash on Win95
  345. //
  346. if (dllHandle != NULL) {
  347. FreeLibrary( dllHandle );
  348. }
  349. if ( hRpcRef != NULL ) {
  350. FreeLibrary( hRpcRef );
  351. hRpcRef = NULL;
  352. }
  353. //
  354. // Terminate service entry locks
  355. //
  356. for ( dwIndex = 0 ; ; dwIndex++ )
  357. {
  358. pEntry = &( InetServiceDllTable[ dwIndex ] );
  359. if ( pEntry->lpServiceName == NULL )
  360. {
  361. break;
  362. }
  363. DeleteCriticalSection( &( pEntry->csLoadLock ) );
  364. }
  365. IIS_PRINTF((buff,"Exiting inetinfo.exe\n"));
  366. #ifndef _NO_TRACING_
  367. DELETE_DEBUG_PRINT_OBJECT();
  368. // DELETE_INITIALIZE_DEBUG()
  369. #endif
  370. DBGPRINTF((
  371. DBG_CONTEXT,
  372. "Exiting main CTC = %d \n",
  373. GetTickCount()
  374. ));
  375. return err;
  376. } // main
  377. DWORD
  378. FindEntryFromDispatchTable(
  379. IN LPSTR pszService
  380. )
  381. {
  382. SERVICE_TABLE_ENTRY * pService;
  383. for(pService = InetServiceDispatchTable;
  384. pService->lpServiceName != NULL;
  385. pService++) {
  386. if ( !lstrcmpi( pService->lpServiceName, pszService)) {
  387. return DIFF(pService - InetServiceDispatchTable);
  388. }
  389. }
  390. //
  391. // We have not found the entry. Set error and return
  392. //
  393. SetLastError( ERROR_INVALID_PARAMETER);
  394. return 0xFFFFFFFF;
  395. } // FindEntryFromDispatchTable()
  396. BOOL
  397. GetDLLNameForDispatchEntryService(
  398. IN LPSTR pszService,
  399. IN OUT CHAR * pszDllName,
  400. IN DWORD cbDllName
  401. )
  402. /*++
  403. Routine Description:
  404. If the image name is not in the static dispatch table, then it might be
  405. in the registry under the value "IISDllName" under the key for the
  406. service. This routine reads the registry for the setting (if existing).
  407. This code allows the exchange folks to install their service DLLs in a
  408. location other than "%systemroot%\inetsrv".
  409. Arguments:
  410. pszService - Service name
  411. pszDllName - Filled with image name
  412. cbDllName - Size of buffer pointed to by pszDllName
  413. Return Value:
  414. TRUE if successful, else FALSE.
  415. --*/
  416. {
  417. HKEY hkey = NULL, hkeyService = NULL;
  418. DWORD err;
  419. DWORD valType;
  420. DWORD nBytes;
  421. BOOL ret = FALSE;
  422. err = RegOpenKeyEx(
  423. HKEY_LOCAL_MACHINE,
  424. REGISTRY_SERVICES_KEY_A,
  425. 0,
  426. KEY_READ,
  427. &hkeyService
  428. );
  429. if (err != ERROR_SUCCESS) {
  430. IIS_PRINTF((buff,
  431. "Inetinfo: Failed to open service key: %ld\n", err));
  432. goto Cleanup;
  433. }
  434. err = RegOpenKeyEx(
  435. hkeyService,
  436. pszService,
  437. 0,
  438. KEY_READ,
  439. &hkey
  440. );
  441. if (err != ERROR_SUCCESS) {
  442. IIS_PRINTF((buff,
  443. "Inetinfo: Failed to open service key for %s: %ld\n",
  444. pszService, err));
  445. goto Cleanup;
  446. }
  447. nBytes = cbDllName;
  448. err = RegQueryValueEx(
  449. hkey,
  450. REGISTRY_VALUE_IISSERVICE_DLL_PATH_NAME_A,
  451. NULL,
  452. &valType,
  453. (LPBYTE)pszDllName,
  454. &nBytes);
  455. if ( err == ERROR_SUCCESS &&
  456. ( valType == REG_SZ || valType == REG_EXPAND_SZ ) )
  457. {
  458. IIS_PRINTF((buff,
  459. "Service Dll is %s", pszDllName));
  460. ret = TRUE;
  461. }
  462. Cleanup:
  463. if (hkey != NULL) {
  464. RegCloseKey( hkey );
  465. }
  466. if (hkeyService != NULL) {
  467. RegCloseKey( hkeyService );
  468. }
  469. return ret;
  470. }
  471. VOID
  472. InetinfoStartService (
  473. IN DWORD argc,
  474. IN LPSTR argv[]
  475. )
  476. /*++
  477. Routine Description:
  478. This routine loads the DLL that contains a service and calls its
  479. main routine.
  480. Arguments:
  481. DllName - name of the DLL
  482. argc, argv - Passed through to the service
  483. Return Value:
  484. None.
  485. --*/
  486. {
  487. HMODULE dllHandle;
  488. PINETSVCS_SERVICE_DLL_ENTRY serviceEntry;
  489. BOOL ok;
  490. DWORD Error;
  491. CHAR tmpDllName[MAX_PATH+1];
  492. LPSTR DllName;
  493. DWORD dwIndex;
  494. //
  495. // If we need to refuse to start services, do so.
  496. //
  497. if ( RefuseStartup ) {
  498. AbortService(argv[0], ERROR_INVALID_PARAMETER);
  499. return;
  500. }
  501. //
  502. // Find the Dll Name for requested service
  503. //
  504. dwIndex = FindEntryFromDispatchTable( argv[0] );
  505. if ( dwIndex == 0xFFFFFFFF ) {
  506. if ( GetDLLNameForDispatchEntryService( argv[0],
  507. tmpDllName,
  508. sizeof( tmpDllName ) ) ) {
  509. IIS_PRINTF((buff,
  510. "Service %s has path set in registry. Assuming %s\n",
  511. argv[0],
  512. tmpDllName));
  513. DllName = tmpDllName;
  514. }
  515. else if ( strlen(argv[0]) < (MAX_PATH-4) ) {
  516. strcpy(tmpDllName, argv[0]);
  517. strcat(tmpDllName, ".dll");
  518. IIS_PRINTF((buff,"Service %s not on primary list. Assuming %s\n",
  519. argv[0], tmpDllName));
  520. DllName = tmpDllName;
  521. } else {
  522. Error = ERROR_INSUFFICIENT_BUFFER;
  523. IIS_PRINTF((buff,
  524. "Inetinfo: Failed To Find Dll For %s : %ld\n",
  525. argv[0], Error));
  526. AbortService( argv[0], Error);
  527. return;
  528. }
  529. }
  530. else
  531. {
  532. DllName = InetServiceDllTable[ dwIndex ].lpDllName;
  533. }
  534. //
  535. // Load the DLL that contains the service.
  536. //
  537. if ( dwIndex != 0xFFFFFFFF )
  538. {
  539. EnterCriticalSection( &( InetServiceDllTable[ dwIndex ].csLoadLock ) );
  540. }
  541. dllHandle = LoadLibraryEx( DllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH );
  542. if ( dllHandle == NULL ) {
  543. Error = GetLastError();
  544. IIS_PRINTF((buff,
  545. "Inetinfo: Failed to load DLL %s: %ld\n",
  546. DllName, Error));
  547. AbortService(argv[0], Error);
  548. goto Finished;
  549. }
  550. //
  551. // Get the address of the service's main entry point. This
  552. // entry point has a well-known name.
  553. //
  554. serviceEntry = (PINETSVCS_SERVICE_DLL_ENTRY)GetProcAddress(
  555. dllHandle,
  556. INETSVCS_ENTRY_POINT_STRING
  557. );
  558. if ( serviceEntry == NULL ) {
  559. Error = GetLastError();
  560. IIS_PRINTF((buff,
  561. "Inetinfo: Can't find entry %s in DLL %s: %ld\n",
  562. INETSVCS_ENTRY_POINT_STRING, DllName, Error));
  563. AbortService(argv[0], Error);
  564. } else {
  565. //
  566. // Call the service's main entry point. This call doesn't return
  567. // until the service exits.
  568. //
  569. serviceEntry( argc, argv, &InetinfoGlobalData );
  570. }
  571. //
  572. // wait for the control dispatcher routine to return. This
  573. // works around a problem where simptcp was crashing because the
  574. // FreeLibrary() was happenning before the control routine returned.
  575. //
  576. Sleep( 500 );
  577. //
  578. // Unload the DLL.
  579. //
  580. ok = FreeLibrary( dllHandle );
  581. if ( !ok ) {
  582. IIS_PRINTF((buff,
  583. "INETSVCS: Can't unload DLL %s: %ld\n",
  584. DllName, GetLastError()));
  585. }
  586. Finished:
  587. if ( dwIndex != 0xFFFFFFFF )
  588. {
  589. LeaveCriticalSection( &( InetServiceDllTable[ dwIndex ].csLoadLock ) );
  590. }
  591. return;
  592. } // InetinfoStartService
  593. VOID
  594. DummyCtrlHandler(
  595. DWORD Opcode
  596. )
  597. /*++
  598. Routine Description:
  599. This is a dummy control handler which is only used if we can't load
  600. a services DLL entry point. Then we need this so we can send the
  601. status back to the service controller saying we are stopped, and why.
  602. Arguments:
  603. OpCode - Ignored
  604. Return Value:
  605. None.
  606. --*/
  607. {
  608. return;
  609. } // DummyCtrlHandler
  610. VOID
  611. AbortService(
  612. LPSTR ServiceName,
  613. DWORD Error)
  614. /*++
  615. Routine Description:
  616. This is called if we can't load the entry point for a service. It
  617. gets a handle so it can call SetServiceStatus saying we are stopped
  618. and why.
  619. Arguments:
  620. ServiceName - the name of the service that couldn't be started
  621. Error - the reason it couldn't be started
  622. Return Value:
  623. None.
  624. --*/
  625. {
  626. SERVICE_STATUS_HANDLE GenericServiceStatusHandle;
  627. SERVICE_STATUS GenericServiceStatus;
  628. if (!g_fRunAsExe) {
  629. GenericServiceStatus.dwServiceType = SERVICE_WIN32;
  630. GenericServiceStatus.dwCurrentState = SERVICE_STOPPED;
  631. GenericServiceStatus.dwControlsAccepted = SERVICE_CONTROL_STOP;
  632. GenericServiceStatus.dwCheckPoint = 0;
  633. GenericServiceStatus.dwWaitHint = 0;
  634. GenericServiceStatus.dwWin32ExitCode = Error;
  635. GenericServiceStatus.dwServiceSpecificExitCode = 0;
  636. GenericServiceStatusHandle = RegisterServiceCtrlHandler(
  637. ServiceName,
  638. DummyCtrlHandler);
  639. if (GenericServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {
  640. IIS_PRINTF((buff,
  641. "[Inetinfo]RegisterServiceCtrlHandler[%s] failed %d\n",
  642. ServiceName, GetLastError()));
  643. } else if (!SetServiceStatus (GenericServiceStatusHandle,
  644. &GenericServiceStatus)) {
  645. IIS_PRINTF((buff,
  646. "[Inetinfo]SetServiceStatus[%s] error %ld\n",
  647. ServiceName, GetLastError()));
  648. }
  649. }
  650. return;
  651. };
  652. VOID
  653. StartDispatchTable(
  654. VOID
  655. )
  656. /*++
  657. Routine Description:
  658. Returns the dispatch table to use. It uses the default if
  659. the DispatchEntries value key does not exist
  660. Arguments:
  661. None.
  662. Return Value:
  663. Pointer to the dispatch table to use.
  664. --*/
  665. {
  666. LPSERVICE_TABLE_ENTRY dispatchTable = InetServiceDispatchTable;
  667. LPSERVICE_TABLE_ENTRY tableEntry = NULL;
  668. LPBYTE buffer;
  669. HKEY hKey = NULL;
  670. DWORD i;
  671. DWORD err;
  672. DWORD valType;
  673. DWORD nBytes = 0;
  674. DWORD nEntries = 0;
  675. PCHAR entry;
  676. BOOL IsIisAdmin = TRUE;
  677. HMODULE dllHandle;
  678. PIISADMIN_SERVICE_DLL_EXEENTRY IisAdminExeEntry = NULL;
  679. PIISADMIN_SERVICE_DLL_EXEEXIT IisAdminExeExit = NULL;
  680. DWORD dwW3svcNoAuth;
  681. //
  682. // See if need to augment the dispatcher table
  683. //
  684. err = RegOpenKeyEx(
  685. HKEY_LOCAL_MACHINE,
  686. REGISTRY_KEY_INETINFO_PARAMETERS_A,
  687. 0,
  688. KEY_READ,
  689. &hKey
  690. );
  691. if ( err != ERROR_SUCCESS ) {
  692. hKey = NULL;
  693. goto start_dispatch;
  694. }
  695. //
  696. // See if mono service
  697. //
  698. nBytes = sizeof(dwW3svcNoAuth);
  699. if ( RegQueryValueEx(
  700. hKey,
  701. INETA_W3ONLY_NO_AUTH,
  702. NULL,
  703. &valType,
  704. (LPBYTE)&dwW3svcNoAuth,
  705. &nBytes
  706. ) == ERROR_SUCCESS && valType == REG_DWORD ) {
  707. g_fW3svcNoAuth = !!dwW3svcNoAuth;
  708. }
  709. if ( g_fW3svcNoAuth ) {
  710. dllHandle = LoadLibrary(IISADMIN_NAME);
  711. if ( dllHandle == NULL ) {
  712. err = GetLastError();
  713. IIS_PRINTF((buff,
  714. "Inetinfo: Failed to load DLL %s: %ld\n",
  715. IISADMIN_NAME, err));
  716. return;
  717. }
  718. //
  719. // Get the address of the service's main entry point. This
  720. // entry point has a well-known name.
  721. //
  722. IisAdminExeEntry = (PIISADMIN_SERVICE_DLL_EXEENTRY)GetProcAddress(
  723. dllHandle,
  724. IISADMIN_EXEENTRY_STRING
  725. );
  726. if (IisAdminExeEntry == NULL ) {
  727. err = GetLastError();
  728. IIS_PRINTF((buff,
  729. "Inetinfo: Can't find entry %s in DLL %s: %ld\n",
  730. IISADMIN_EXEENTRY_STRING, IISADMIN_NAME, err));
  731. return;
  732. }
  733. IisAdminExeExit = (PIISADMIN_SERVICE_DLL_EXEEXIT)GetProcAddress(
  734. dllHandle,
  735. IISADMIN_EXEEXIT_STRING
  736. );
  737. if (IisAdminExeExit == NULL ) {
  738. err = GetLastError();
  739. IIS_PRINTF((buff,
  740. "Inetinfo: Can't find entry %s in DLL %s: %ld\n",
  741. IISADMIN_EXEEXIT_STRING, IISADMIN_NAME, err);
  742. );
  743. return;
  744. }
  745. if (!IisAdminExeEntry( FALSE, TRUE, TRUE )) {
  746. IIS_PRINTF((buff,"IISadmin init failed\n"));
  747. return;
  748. }
  749. IsIisAdmin = FALSE;
  750. dispatchTable = W3ServiceDispatchTable;
  751. goto start_dispatch;
  752. }
  753. //
  754. // See if the value exists and get the size of the buffer needed
  755. //
  756. nBytes = 0;
  757. err = RegQueryValueEx(
  758. hKey,
  759. REGISTRY_VALUE_INETINFO_DISPATCH_ENTRIES_A,
  760. NULL,
  761. &valType,
  762. NULL,
  763. &nBytes
  764. );
  765. if ( (err != ERROR_SUCCESS) || (nBytes <= sizeof(CHAR)) ) {
  766. goto start_dispatch;
  767. }
  768. //
  769. // Allocate nBytes to query the buffer
  770. //
  771. buffer = (LPBYTE)LocalAlloc(0, nBytes);
  772. if ( buffer == NULL ) {
  773. goto start_dispatch;
  774. }
  775. //
  776. // Get the values
  777. //
  778. err = RegQueryValueEx(
  779. hKey,
  780. REGISTRY_VALUE_INETINFO_DISPATCH_ENTRIES_A,
  781. NULL,
  782. &valType,
  783. buffer,
  784. &nBytes
  785. );
  786. if ( (err != ERROR_SUCCESS) || (valType != REG_MULTI_SZ) ) {
  787. LocalFree(buffer);
  788. goto start_dispatch;
  789. }
  790. //
  791. // Walk the list and see how many entries we have. Remove the list
  792. // terminator from the byte count
  793. //
  794. nBytes -= sizeof(CHAR);
  795. for ( i = 0, entry = (PCHAR)buffer;
  796. i < nBytes;
  797. i += sizeof(CHAR) ) {
  798. if ( *entry++ == '\0' ) {
  799. nEntries++;
  800. }
  801. }
  802. if ( nEntries == 0 ) {
  803. LocalFree(buffer);
  804. goto start_dispatch;
  805. }
  806. //
  807. // Add the number of entries in the default list (including the NULL entry)
  808. //
  809. nEntries += sizeof(InetServiceDispatchTable) / sizeof(SERVICE_TABLE_ENTRY);
  810. //
  811. // Now we need to allocate the new dispatch table
  812. //
  813. tableEntry = (LPSERVICE_TABLE_ENTRY)
  814. LocalAlloc(0, nEntries * sizeof(SERVICE_TABLE_ENTRY));
  815. if ( tableEntry == NULL ) {
  816. LocalFree(buffer);
  817. goto start_dispatch;
  818. }
  819. //
  820. // set the dispatch table pointer to the new table
  821. //
  822. dispatchTable = tableEntry;
  823. //
  824. // Populate the table starting with the defaults
  825. //
  826. for (i=0; InetServiceDispatchTable[i].lpServiceName != NULL; i++ ) {
  827. tableEntry->lpServiceName =
  828. InetServiceDispatchTable[i].lpServiceName;
  829. tableEntry->lpServiceProc =
  830. InetServiceDispatchTable[i].lpServiceProc;
  831. tableEntry++;
  832. }
  833. //
  834. // Now let's add the ones specified in the registry
  835. //
  836. entry = (PCHAR)buffer;
  837. tableEntry->lpServiceName = entry;
  838. tableEntry->lpServiceProc = InetinfoStartService;
  839. tableEntry++;
  840. //
  841. // Skip the first char and the last NULL terminator.
  842. // This is needed because we already added the first one.
  843. //
  844. for ( i = 2*sizeof(CHAR); i < nBytes; i += sizeof(CHAR) ) {
  845. if ( *entry++ == '\0' ) {
  846. tableEntry->lpServiceName = entry;
  847. tableEntry->lpServiceProc = InetinfoStartService;
  848. tableEntry++;
  849. }
  850. }
  851. //
  852. // setup sentinel entry
  853. //
  854. tableEntry->lpServiceName = NULL;
  855. tableEntry->lpServiceProc = NULL;
  856. start_dispatch:
  857. if ( hKey != NULL ) {
  858. RegCloseKey(hKey);
  859. }
  860. W3SVCLauncher* pLauncher = new W3SVCLauncher();
  861. if (pLauncher==NULL)
  862. {
  863. IIS_PRINTF((buff,
  864. "Inetinfo: Can not launch the W3SVC launching class %lu\n",
  865. GetLastError()));
  866. }
  867. else
  868. {
  869. pLauncher->StartListening();
  870. }
  871. //
  872. // Call StartServiceCtrlDispatcher to set up the control interface.
  873. // The API won't return until all services have been terminated. At that
  874. // point, we just exit.
  875. //
  876. if (! StartServiceCtrlDispatcher (
  877. dispatchTable
  878. )) {
  879. //
  880. // Log an event for failing to start control dispatcher
  881. //
  882. IIS_PRINTF((buff,
  883. "Inetinfo: Failed to start control dispatcher %lu\n",
  884. GetLastError()));
  885. }
  886. DBGPRINTF((
  887. DBG_CONTEXT,
  888. "All services have shutdown CTC = %d \n",
  889. GetTickCount()
  890. ));
  891. if (pLauncher)
  892. {
  893. pLauncher->StopListening();
  894. delete pLauncher;
  895. pLauncher = NULL;
  896. }
  897. DBGPRINTF((
  898. DBG_CONTEXT,
  899. "Completed all W3SVC new code CTC = %d \n",
  900. GetTickCount()
  901. ));
  902. // Now that we have returned from the StartServiceCtrlDispatcher it means
  903. // that even IISAdmin has shutdown. This means that W3svc is no longer running
  904. // and that we do not need to keep listening for WAS to tell us to start W3WP.
  905. // Therefore we need to single the thread to complete so that inetinfo.exe shutsdown
  906. // correctly.
  907. //
  908. // free table if allocated
  909. //
  910. if ( dispatchTable != InetServiceDispatchTable &&
  911. dispatchTable != W3ServiceDispatchTable ) {
  912. LocalFree( dispatchTable );
  913. LocalFree( buffer );
  914. }
  915. if (!IsIisAdmin) {
  916. IisAdminExeExit();
  917. FreeLibrary( dllHandle );
  918. }
  919. DBGPRINTF((
  920. DBG_CONTEXT,
  921. "Exiting StartDispatchTable CTC = %d \n",
  922. GetTickCount()
  923. ));
  924. return;
  925. } // StartDispatchTable
  926. BOOL
  927. LoadPreloadDlls(
  928. HMODULE * * ppPreloadDllHandles
  929. )
  930. /*++
  931. Routine Description:
  932. Force pre-loading of any DLLs listed in the associated registry key.
  933. This is to support DLLs that have code which must run before other parts
  934. of inetinfo start.
  935. Arguments:
  936. On input, an (uninitialized) pointer to an array of module handles. This
  937. array is allocated, filled out, and returned to the caller by this
  938. function. The caller must eventually call UnloadPreloadDlls on this array
  939. in order to close the handles and release the memory.
  940. Return Value:
  941. TRUE on success, FALSE on failure.
  942. --*/
  943. {
  944. BOOL bSuccess = TRUE;
  945. HKEY hKey = NULL;
  946. DWORD err;
  947. DWORD cbBufferLen;
  948. DWORD valType;
  949. LPBYTE pbBuffer = NULL;
  950. DWORD i;
  951. PCHAR pszTemp = NULL;
  952. DWORD nEntries;
  953. PCHAR pszEntry = NULL;
  954. DWORD curEntry;
  955. *ppPreloadDllHandles = NULL;
  956. err = RegOpenKeyEx(
  957. HKEY_LOCAL_MACHINE,
  958. REGISTRY_KEY_INETINFO_PARAMETERS_A,
  959. 0,
  960. KEY_QUERY_VALUE,
  961. &hKey
  962. );
  963. if ( err != ERROR_SUCCESS ) {
  964. // Note: not considered an error if the key is not there
  965. hKey = NULL;
  966. goto Exit;
  967. }
  968. //
  969. // See if the value exists and get the size of the buffer needed
  970. //
  971. cbBufferLen = 0;
  972. err = RegQueryValueEx(
  973. hKey,
  974. REGISTRY_VALUE_INETINFO_PRELOAD_DLLS_A,
  975. NULL,
  976. &valType,
  977. NULL,
  978. &cbBufferLen
  979. );
  980. //
  981. // Check for no value or an empty value (double null terminated).
  982. //
  983. if ( ( err != ERROR_SUCCESS ) || ( cbBufferLen <= 2 * sizeof(CHAR) ) )
  984. {
  985. // Note: not considered an error if the value is not there
  986. goto Exit;
  987. }
  988. //
  989. // Allocate cbBufferLen in order to fetch the data
  990. //
  991. pbBuffer = (LPBYTE)LocalAlloc(
  992. 0,
  993. cbBufferLen
  994. );
  995. if ( pbBuffer == NULL )
  996. {
  997. bSuccess = FALSE;
  998. goto Exit;
  999. }
  1000. //
  1001. // Get the values
  1002. //
  1003. err = RegQueryValueEx(
  1004. hKey,
  1005. REGISTRY_VALUE_INETINFO_PRELOAD_DLLS_A,
  1006. NULL,
  1007. &valType,
  1008. pbBuffer,
  1009. &cbBufferLen
  1010. );
  1011. if ( ( err != ERROR_SUCCESS ) || ( valType != REG_MULTI_SZ ) )
  1012. {
  1013. bSuccess = FALSE;
  1014. goto Exit;
  1015. }
  1016. //
  1017. // Walk the list and see how many entries we have. Ignore the list
  1018. // terminator in the last byte of the buffer.
  1019. //
  1020. nEntries = 0;
  1021. pszTemp = (PCHAR)pbBuffer;
  1022. for ( i = 0; i < ( cbBufferLen - sizeof(CHAR) ) ; i += sizeof(CHAR) )
  1023. {
  1024. if ( *pszTemp == '\0' )
  1025. {
  1026. nEntries++;
  1027. }
  1028. pszTemp++;
  1029. }
  1030. //
  1031. // Allocate the array of handles, with room for a sentinel entry
  1032. //
  1033. *ppPreloadDllHandles = (HMODULE *)LocalAlloc(
  1034. 0,
  1035. ( nEntries + 1 ) * sizeof(HMODULE)
  1036. );
  1037. if ( *ppPreloadDllHandles == NULL )
  1038. {
  1039. bSuccess = FALSE;
  1040. goto Exit;
  1041. }
  1042. //
  1043. // Now attempt to load each DLL, and save the handle in the array
  1044. //
  1045. pszTemp = (PCHAR)pbBuffer;
  1046. pszEntry = (PCHAR)pbBuffer;
  1047. curEntry = 0;
  1048. for ( i = 0; i < ( cbBufferLen - sizeof(CHAR) ) ; i += sizeof(CHAR) )
  1049. {
  1050. if ( *pszTemp == '\0' )
  1051. {
  1052. //
  1053. // We've hit the end of one of the SZs in the Multi-SZ;
  1054. // Load the DLL
  1055. //
  1056. (*ppPreloadDllHandles)[curEntry] = LoadLibrary( pszEntry );
  1057. if ( (*ppPreloadDllHandles)[curEntry] == NULL )
  1058. {
  1059. IIS_PRINTF(( buff, "Preloading FAILED for DLL: %s\n", pszEntry ));
  1060. }
  1061. else
  1062. {
  1063. IIS_PRINTF(( buff, "Preloaded DLL: %s\n", pszEntry ));
  1064. // Only move to the next slot if we got a valid handle
  1065. curEntry++;
  1066. }
  1067. // Set the next entry pointer past the current null char
  1068. pszEntry = pszTemp + sizeof(CHAR);
  1069. }
  1070. pszTemp++;
  1071. }
  1072. // Put in a sentinel at the end of the array
  1073. (*ppPreloadDllHandles)[curEntry] = NULL;
  1074. Exit:
  1075. if ( hKey != NULL )
  1076. {
  1077. RegCloseKey( hKey );
  1078. }
  1079. if ( pbBuffer != NULL )
  1080. {
  1081. LocalFree( pbBuffer );
  1082. }
  1083. return bSuccess;
  1084. } // LoadPreloadDlls
  1085. VOID
  1086. UnloadPreloadDlls(
  1087. HMODULE * * ppPreloadDllHandles
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. Unload any DLLs which were preloaded by LoadPreloadDlls.
  1092. Arguments:
  1093. Pointer to an array of module handles. Each handle will be freed,
  1094. and then the memory of the array will be LocalFree()ed by this function.
  1095. Return Value:
  1096. None.
  1097. --*/
  1098. {
  1099. HMODULE * pHandleArray = *ppPreloadDllHandles;
  1100. if ( pHandleArray != NULL )
  1101. {
  1102. IIS_PRINTF(( buff, "Unloading Preloaded DLLs\n" ));
  1103. while ( *pHandleArray != NULL )
  1104. {
  1105. FreeLibrary( *pHandleArray );
  1106. pHandleArray++;
  1107. }
  1108. LocalFree( *ppPreloadDllHandles );
  1109. *ppPreloadDllHandles = NULL;
  1110. }
  1111. return;
  1112. } // UnloadPreloadDlls