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.

789 lines
19 KiB

  1. /**********************************************************************/
  2. /** Microsoft Windows NT **/
  3. /** Copyright(c) Microsoft Corp., 1993 **/
  4. /**********************************************************************/
  5. /*
  6. main.cxx
  7. This module contains the main startup code for the SMTP Service.
  8. FILE HISTORY:
  9. KeithMo 07-Mar-1993 Created.
  10. JohnL ????
  11. MuraliK 11-July-1995 Used Ipc() functions from Inetsvcs.dll
  12. */
  13. #define INCL_INETSRV_INCS
  14. #include "smtpinc.h"
  15. #include "inetsvcs.h"
  16. #include <metacach.hxx>
  17. #include <dbgutil.h>
  18. // ATL Header files
  19. #define _ATL_NO_DEBUG_CRT
  20. #define _ASSERTE _ASSERT
  21. #define _WINDLL
  22. #include "atlbase.h"
  23. extern CComModule _Module;
  24. #include "atlcom.h"
  25. #undef _WINDLL
  26. #ifdef _ATL_STATIC_REGISTRY
  27. #include <statreg.h>
  28. #include <statreg.cpp>
  29. #endif
  30. #include <atlimpl.cpp>
  31. //
  32. // RPC related includes
  33. //
  34. extern "C" {
  35. #include <inetinfo.h>
  36. #include <smtpsvc.h>
  37. };
  38. #include <smtpinet.h>
  39. extern DWORD g_cMaxConnectionObjs;
  40. BOOL
  41. InitializeSmtpServiceRpc(
  42. IN LPCSTR pszServiceName,
  43. IN RPC_IF_HANDLE hRpcInterface
  44. );
  45. BOOL CleanupSmtpServiceRpc(
  46. VOID
  47. );
  48. //
  49. // Private constants.
  50. //
  51. BOOL fAnySecureFilters = FALSE;
  52. //
  53. // for PDC hack
  54. //
  55. #define VIRTUAL_ROOTS_KEY_A "Virtual Roots"
  56. #define HTTP_EXT_MAPS "Script Map"
  57. #define SMTP_MODULE_NAME "smtpsvc"
  58. //
  59. // Global startup named event
  60. //
  61. DWORD GlobalInitializeStatus = 0;
  62. BOOL g_ServiceBooted = FALSE;
  63. //
  64. // Private globals.
  65. //
  66. #define INITIALIZE_IPC 0x00000001
  67. #define INITIALIZE_SOCKETS 0x00000002
  68. #define INITIALIZE_ACCESS 0x00000004
  69. #define INITIALIZE_SERVICE 0x00000008
  70. #define INITIALIZE_CONNECTIONS 0x00000010
  71. #define INITIALIZE_DISCOVERY 0x00000020
  72. #define INITIALIZE_RPC 0x00000040
  73. #define INITIALIZE_GLOBALS 0x00000080
  74. #define INITIALIZE_COMMON_DLLS 0x00000100
  75. #define INITIALIZE_ROUTE_SORT 0x00000200
  76. #define INITIALIZE_FIO 0x00000400
  77. DEFINE_TSVC_INFO_INTERFACE();
  78. DECLARE_DEBUG_PRINTS_OBJECT();
  79. DECLARE_DEBUG_VARIABLE();
  80. //
  81. // The following critical section synchronizes execution in ServiceEntry().
  82. // This is necessary because the NT Service Controller may reissue a service
  83. // start notification immediately after we have set our status to stopped.
  84. // This can lead to an unpleasant race condition in ServiceEntry() as one
  85. // thread cleans up global state as another thread is initializing it.
  86. //
  87. CRITICAL_SECTION g_csServiceEntryLock;
  88. //
  89. // Private prototypes.
  90. //
  91. extern VOID SmtpOnConnect( IN SOCKET sNew,
  92. IN SOCKADDR_IN * psockaddr, //Should be SOCKADDR *
  93. IN PVOID pEndpointContext,
  94. IN PVOID pAtqEndpointObject );
  95. extern VOID
  96. SmtpOnConnectEx(
  97. VOID * patqContext,
  98. DWORD cbWritten,
  99. DWORD err,
  100. OVERLAPPED * lpo
  101. );
  102. VOID
  103. SmtpCompletion(
  104. PVOID pvContext,
  105. DWORD cbWritten,
  106. DWORD dwCompletionStatus,
  107. OVERLAPPED * lpo
  108. );
  109. APIERR InitializeService( LPVOID pContext );
  110. APIERR TerminateService( LPVOID pContext );
  111. VOID TerminateInstances( PSMTP_IIS_SERVICE pService);
  112. /************************************************************
  113. * Symbolic Constants
  114. ************************************************************/
  115. static TCHAR szTcpipPath[] = TEXT("System\\CurrentControlSet\\Services\\Tcpip\\Parameters");
  116. /************************************************************
  117. * ATL Module
  118. ************************************************************/
  119. CComModule _Module;
  120. BEGIN_OBJECT_MAP(ObjectMap)
  121. END_OBJECT_MAP()
  122. #if 0
  123. /************************************************************
  124. * ATL Module
  125. ************************************************************/
  126. CComModule _Module;
  127. BEGIN_OBJECT_MAP(ObjectMap)
  128. END_OBJECT_MAP()
  129. #endif
  130. //+---------------------------------------------------------------------------
  131. //
  132. // Function:
  133. //
  134. // DllEntryPoint
  135. //
  136. // Synopsis:
  137. // Arguments:
  138. // Returns:
  139. // See Win32 SDK
  140. //
  141. // History:
  142. //
  143. // Richard Kamicar (rkamicar) 5 January 1996
  144. //
  145. // Notes:
  146. //
  147. // If we find we need this per service, we can move it out of here..
  148. //
  149. //----------------------------------------------------------------------------
  150. BOOL WINAPI
  151. DllEntryPoint(HINSTANCE hInst, DWORD dwReason, LPVOID lpvContext)
  152. {
  153. switch (dwReason)
  154. {
  155. case DLL_PROCESS_ATTACH:
  156. CREATE_DEBUG_PRINT_OBJECT( SMTP_MODULE_NAME);
  157. LOAD_DEBUG_FLAGS_FROM_REG_STR("Software\\Microsoft\\Exchange\\SmtpSvc", 0);
  158. //
  159. // To help performance, cancel thread attach and detach notifications
  160. //
  161. _Module.Init(ObjectMap, hInst);
  162. DisableThreadLibraryCalls((HMODULE) hInst);
  163. InitializeCriticalSection( &g_csServiceEntryLock );
  164. break;
  165. case DLL_PROCESS_DETACH:
  166. // Shutdown ATL
  167. _Module.Term();
  168. #ifdef _NO_TRACING_
  169. DBG_CLOSE_LOG_FILE();
  170. #endif
  171. DELETE_DEBUG_PRINT_OBJECT();
  172. DeleteCriticalSection( &g_csServiceEntryLock );
  173. break;
  174. case DLL_THREAD_ATTACH:
  175. break;
  176. case DLL_THREAD_DETACH:
  177. break;
  178. }
  179. return TRUE;
  180. }
  181. BOOL WINAPI DllMain (HANDLE hInst, ULONG dwReason, LPVOID lpvReserve)
  182. {
  183. return DllEntryPoint((HINSTANCE) hInst, dwReason, lpvReserve);
  184. }
  185. //
  186. // Public functions.
  187. //
  188. VOID
  189. ServiceEntry(
  190. DWORD cArgs,
  191. LPSTR pArgs[],
  192. PTCPSVCS_GLOBAL_DATA pGlobalData // unused
  193. )
  194. /*++
  195. Routine:
  196. This is the "real" entrypoint for the service. When
  197. the Service Controller dispatcher is requested to
  198. start a service, it creates a thread that will begin
  199. executing this routine.
  200. Arguments:
  201. cArgs - Number of command line arguments to this service.
  202. pArgs - Pointers to the command line arguments.
  203. Returns:
  204. None. Does not return until service is stopped.
  205. --*/
  206. {
  207. APIERR err = NO_ERROR;
  208. BOOL fInitSvcObject = FALSE;
  209. EnterCriticalSection( &g_csServiceEntryLock );
  210. if ( !InitCommonDlls() )
  211. {
  212. DBGPRINTF(( DBG_CONTEXT,
  213. "[ServiceEntry] InitCommonDlls failed! Bailing\n" ));
  214. err = GetLastError();
  215. LeaveCriticalSection( &g_csServiceEntryLock );
  216. goto notify_scm;
  217. }
  218. InitAsyncTrace();
  219. GlobalInitializeStatus |= INITIALIZE_COMMON_DLLS;
  220. if (!InitializeCache()) goto exit;
  221. GlobalInitializeStatus |= INITIALIZE_FIO;
  222. //
  223. // Initialize Globals
  224. //
  225. err = InitializeGlobals();
  226. if ( err != NO_ERROR )
  227. {
  228. goto exit;
  229. }
  230. GlobalInitializeStatus |= INITIALIZE_GLOBALS;
  231. // Initialize the service status structure.
  232. //
  233. g_pInetSvc = new SMTP_IIS_SERVICE(
  234. SMTP_SERVICE_NAME_A,
  235. SMTP_MODULE_NAME,
  236. SMTP_PARAMETERS_KEY,
  237. INET_SMTP_SVC_ID,
  238. INET_SMTP_SVCLOC_ID,
  239. TRUE,
  240. 0,
  241. SmtpOnConnect,
  242. SmtpOnConnectEx,
  243. SmtpCompletion
  244. );
  245. //
  246. // If we couldn't allocate memory for the service info struct, then the
  247. // machine is really hosed.
  248. //
  249. if( ( g_pInetSvc != NULL ) && g_pInetSvc->IsActive() )
  250. {
  251. err = ((SMTP_IIS_SERVICE *)g_pInetSvc)->LoadAdvancedQueueingDll();
  252. if( err != NO_ERROR )
  253. goto exit;
  254. fInitSvcObject = TRUE;
  255. err = g_pInetSvc->StartServiceOperation(
  256. SERVICE_CTRL_HANDLER(),
  257. InitializeService,
  258. TerminateService
  259. );
  260. if ( err )
  261. {
  262. //
  263. // The event has already been logged
  264. //
  265. DBGPRINTF(( DBG_CONTEXT,
  266. "SMTP ServiceEntry: StartServiceOperation returned %d\n",
  267. err ));
  268. }
  269. }
  270. else if (g_pInetSvc == NULL)
  271. {
  272. err = ERROR_NOT_ENOUGH_MEMORY;
  273. }
  274. else
  275. {
  276. err = g_pInetSvc->QueryCurrentServiceError();
  277. }
  278. exit:
  279. if ( g_pInetSvc != NULL )
  280. {
  281. g_pInetSvc->CloseService( );
  282. }
  283. TerminateGlobals( );
  284. if( GlobalInitializeStatus & INITIALIZE_FIO)
  285. {
  286. TerminateCache();
  287. }
  288. if( GlobalInitializeStatus & INITIALIZE_COMMON_DLLS)
  289. {
  290. TerminateCommonDlls();
  291. }
  292. TermAsyncTrace();
  293. LeaveCriticalSection( &g_csServiceEntryLock );
  294. notify_scm:
  295. //
  296. // We need to tell the Service Control Manager that the service
  297. // is stopped if we haven't called g_pInetSvc->StartServiceOperation.
  298. // 1) InitCommonDlls fails, or
  299. // 2) InitializeGlobals failed, or
  300. // 3) new operator failed, or
  301. // 4) SMTP_IIS_SERVICE constructor couldn't initialize properly
  302. //
  303. if ( !fInitSvcObject ) {
  304. SERVICE_STATUS_HANDLE hsvcStatus;
  305. SERVICE_STATUS svcStatus;
  306. hsvcStatus = RegisterServiceCtrlHandler( SMTP_SERVICE_NAME,
  307. SERVICE_CTRL_HANDLER() );
  308. if ( hsvcStatus != NULL_SERVICE_STATUS_HANDLE ) {
  309. svcStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
  310. svcStatus.dwCurrentState = SERVICE_STOPPED;
  311. svcStatus.dwWin32ExitCode = err;
  312. svcStatus.dwServiceSpecificExitCode = err;
  313. svcStatus.dwControlsAccepted = 0;
  314. svcStatus.dwCheckPoint = 0;
  315. svcStatus.dwWaitHint = 0;
  316. SetServiceStatus( hsvcStatus, (LPSERVICE_STATUS) &svcStatus );
  317. }
  318. }
  319. } // ServiceEntry
  320. //
  321. // Private functions.
  322. //
  323. APIERR
  324. InitializeService(
  325. LPVOID pContext
  326. )
  327. /*++
  328. Routine:
  329. This function initializes the various SMTP Service components.
  330. Arguments:
  331. lpContext - Pointer to the service object
  332. Returns:
  333. NO_ERROR if successful, otherwise a Win32
  334. status code.
  335. --*/
  336. {
  337. APIERR err;
  338. DWORD dwErr = NO_ERROR;
  339. PSMTP_IIS_SERVICE psi = (PSMTP_IIS_SERVICE)pContext;
  340. MB mb( (IMDCOM*) psi->QueryMDObject() );
  341. STR TempString;
  342. char szTcpipName[MAX_PATH + 1];
  343. BOOL bUpdatedDomain;
  344. BOOL bUpdatedFQDN;
  345. HRESULT hr;
  346. g_IsShuttingDown = FALSE;
  347. TraceFunctEnter("InitializeService");
  348. DBGPRINTF(( DBG_CONTEXT,
  349. "initializing Smtp service\n" ));
  350. SetLastError(NO_ERROR);
  351. psi->StartHintFunction();
  352. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  353. if (FAILED(hr))
  354. {
  355. DBGPRINTF(( DBG_CONTEXT,
  356. "Cannot CoInitialize, error %lu\n",
  357. hr ));
  358. FatalTrace(0,"Cannot CoInitialize, error %d",hr);
  359. // TraceFunctLeave();
  360. // return hr;
  361. }
  362. g_ProductType = 5;
  363. psi->StartHintFunction();
  364. //g_ProductType = 0;
  365. if ( !mb.Open( "/LM/SMTPSVC/",
  366. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ))
  367. {
  368. DBGPRINTF(( DBG_CONTEXT,
  369. "InitializeService: Cannot open path %s, error %lu\n",
  370. "/LM/SMTPSVC/", GetLastError() ));
  371. g_pInetSvc->ShutdownService( );
  372. TraceFunctLeave();
  373. return ERROR_SERVICE_DISABLED;
  374. }
  375. g_ServiceBooted = TRUE;
  376. //
  377. // Initialize the Default Domain, Fully Qualified Domain Name (FQDN) settings.
  378. // The service will use the default TCP/IP settings in the control panel for these
  379. // values if the user has never modified the settings.
  380. //
  381. DWORD tmp;
  382. if (!mb.GetDword("", MD_UPDATED_DEFAULT_DOMAIN, IIS_MD_UT_SERVER, &tmp))
  383. {
  384. bUpdatedDomain = FALSE;
  385. }
  386. else
  387. {
  388. bUpdatedDomain = !!tmp;
  389. }
  390. if (!mb.GetDword("", MD_UPDATED_FQDN, IIS_MD_UT_SERVER, &tmp))
  391. {
  392. bUpdatedFQDN = FALSE;
  393. }
  394. else
  395. {
  396. bUpdatedFQDN = !!tmp;
  397. }
  398. psi->StartHintFunction();
  399. szTcpipName[0] = '\0';
  400. lstrcpyn(szTcpipName, g_ComputerName, MAX_PATH);
  401. //
  402. // will need to check against TCP/IP settings
  403. //
  404. HKEY hkeyTcpipParam = NULL;
  405. DWORD SizeOfBuffer = 0;
  406. DWORD cbOffset;
  407. DWORD dwType;
  408. DWORD err2;
  409. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szTcpipPath, 0, KEY_QUERY_VALUE, &hkeyTcpipParam) == ERROR_SUCCESS)
  410. {
  411. SizeOfBuffer = MAX_PATH;
  412. err2 = RegQueryValueEx(hkeyTcpipParam, "Hostname", 0, &dwType, (LPBYTE)szTcpipName, &SizeOfBuffer);
  413. if (err2 != ERROR_SUCCESS || SizeOfBuffer <= 1 || dwType != REG_SZ)
  414. {
  415. lstrcpyn(szTcpipName, g_ComputerName, MAX_PATH);
  416. }
  417. else
  418. {
  419. cbOffset = SizeOfBuffer - 1;
  420. szTcpipName[cbOffset] = '.';
  421. SizeOfBuffer = MAX_PATH - (cbOffset);
  422. err2 = RegQueryValueEx(hkeyTcpipParam, "Domain", 0, &dwType, (LPBYTE)szTcpipName + cbOffset + 1, &SizeOfBuffer);
  423. if (err2 != ERROR_SUCCESS || SizeOfBuffer <= 1 || dwType != REG_SZ)
  424. {
  425. szTcpipName[cbOffset] = '\0';
  426. }
  427. }
  428. _VERIFY(RegCloseKey(hkeyTcpipParam) == ERROR_SUCCESS);
  429. }
  430. ((SMTP_IIS_SERVICE *) g_pInetSvc)->SetTcpipName(szTcpipName);
  431. if (!bUpdatedDomain)
  432. {
  433. TempString.Reset();
  434. if(! mb.GetStr("", MD_DEFAULT_DOMAIN_VALUE, IIS_MD_UT_SERVER, &TempString) ||
  435. TempString.IsEmpty())
  436. {
  437. mb.SetString("", MD_DEFAULT_DOMAIN_VALUE, IIS_MD_UT_SERVER, szTcpipName);
  438. }
  439. else
  440. {
  441. if (lstrcmpi(szTcpipName,TempString.QueryStr()))
  442. //
  443. // no match, update
  444. //
  445. {
  446. mb.SetString("", MD_DEFAULT_DOMAIN_VALUE, IIS_MD_UT_SERVER, szTcpipName);
  447. }
  448. }
  449. }
  450. if (!bUpdatedFQDN)
  451. {
  452. TempString.Reset();
  453. if(! mb.GetStr("", MD_FQDN_VALUE, IIS_MD_UT_SERVER, &TempString) ||
  454. TempString.IsEmpty())
  455. {
  456. mb.SetString("", MD_FQDN_VALUE, IIS_MD_UT_SERVER, szTcpipName);
  457. }
  458. else
  459. {
  460. if (lstrcmpi(szTcpipName,TempString.QueryStr()))
  461. //
  462. // no match, update
  463. //
  464. {
  465. mb.SetString("", MD_FQDN_VALUE, IIS_MD_UT_SERVER, szTcpipName);
  466. }
  467. }
  468. }
  469. if (!mb.GetDword("", MD_MAX_MAIL_OBJECTS, IIS_MD_UT_SERVER, &g_cMaxConnectionObjs))
  470. {
  471. g_cMaxConnectionObjs = 5000;
  472. }
  473. mb.Close();
  474. psi->StartHintFunction();
  475. //
  476. // Initialize various components. The ordering of the
  477. // components is somewhat limited. Globals should be
  478. // initialized first, then the event logger. After
  479. // the event logger is initialized, the other components
  480. // may be initialized in any order with one exception.
  481. // InitializeSockets must be the last initialization
  482. // routine called. It kicks off the main socket connection
  483. // thread.
  484. //
  485. if( err = psi->InitializeDiscovery( ))
  486. {
  487. DBGPRINTF(( DBG_CONTEXT,
  488. "psi->InitializeDiscovery failed, error %lu\n",
  489. err ));
  490. FatalTrace(0,"psi->InitializeDiscovery failed %d\n",err);
  491. TraceFunctLeave();
  492. return err;
  493. }
  494. GlobalInitializeStatus |= INITIALIZE_DISCOVERY;
  495. if( err = psi->InitializeSockets( ) )
  496. {
  497. DBGPRINTF(( DBG_CONTEXT,
  498. "cannot initialize service, error %lu\n",
  499. err ));
  500. FatalTrace(0,"psi->InitializeSockets failed %d\n",err);
  501. TraceFunctLeave();
  502. return err;
  503. }
  504. GlobalInitializeStatus |= INITIALIZE_SOCKETS;
  505. psi->StartHintFunction();
  506. if(!InitializeSmtpServiceRpc(SMTP_SERVICE_NAME, smtp_ServerIfHandle))
  507. {
  508. err = GetLastError();
  509. DBGPRINTF(( DBG_CONTEXT,
  510. "cannot initialize RPC service, error %lu\n",
  511. err ));
  512. FatalTrace(0,"InitializeSmtpServiceRpc failed %d\n",err);
  513. TraceFunctLeave();
  514. return err;
  515. }
  516. GlobalInitializeStatus |= INITIALIZE_RPC;
  517. //
  518. // Reset any Service Principal Names (for Kerberos) that may have been
  519. // registered
  520. //
  521. if (psi->ResetServicePrincipalNames()) {
  522. DebugTrace(
  523. 0,
  524. "Unable to reset Kerberos Principal Names %lu, will try later",
  525. GetLastError());
  526. }
  527. //
  528. // Read and activate all the instances configured
  529. //
  530. InitializeInstances( psi );
  531. //
  532. // Success!
  533. //
  534. DBGPRINTF(( DBG_CONTEXT, "SMTP Service initialized\n" ));
  535. TraceFunctLeave();
  536. return NO_ERROR;
  537. } // InitializeService
  538. APIERR TerminateService(IN LPVOID pContext)
  539. /*++
  540. Routine:
  541. This function cleans up the various SMTP Service components.
  542. Arguments:
  543. pContext - Pointer to the service object
  544. Returns:
  545. NO_ERROR if successful, otherwise a Win32
  546. status code.
  547. --*/
  548. {
  549. PSMTP_IIS_SERVICE psi = (PSMTP_IIS_SERVICE)pContext;
  550. DWORD err;
  551. TraceFunctEnter("TerminateService");
  552. if(!g_ServiceBooted)
  553. {
  554. ErrorTrace(NULL, "Smtp service not started, returning");
  555. return NO_ERROR;
  556. }
  557. g_ServiceBooted = FALSE ;
  558. g_IsShuttingDown = TRUE;
  559. DBG_ASSERT( pContext == g_pInetSvc);
  560. DBGPRINTF(( DBG_CONTEXT,
  561. " SMTP terminating service\n" ));
  562. //
  563. // Components should be terminated in reverse
  564. // initialization order.
  565. //
  566. //get an exclusive lock on the server.
  567. //this will wait until all RPCs have
  568. //exited out of the server and then
  569. //return
  570. psi->AcquireServiceExclusiveLock();
  571. psi->ReleaseServiceExclusiveLock();
  572. TerminateInstances(psi);
  573. g_pInetSvc->ShutdownService( );
  574. if( GlobalInitializeStatus & INITIALIZE_DISCOVERY)
  575. {
  576. if ( (err = psi->TerminateDiscovery()) != NO_ERROR)
  577. {
  578. DBGPRINTF(( DBG_CONTEXT, "TerminateDiscovery() failed. Error = %u\n",
  579. err));
  580. }
  581. }
  582. if( GlobalInitializeStatus & INITIALIZE_SOCKETS)
  583. {
  584. psi->CleanupSockets( );
  585. }
  586. TsFlushMetaCache(METACACHE_SMTP_SERVER_ID,TRUE);
  587. if( GlobalInitializeStatus & INITIALIZE_RPC)
  588. {
  589. CleanupSmtpServiceRpc();
  590. }
  591. CoFreeUnusedLibraries();
  592. CoUninitialize();
  593. DBGPRINTF(( DBG_CONTEXT,"service terminated\n" ));
  594. TraceFunctLeave();
  595. return NO_ERROR;
  596. } // TerminateService