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.

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