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.

1452 lines
40 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. globals.cxx
  5. Abstract:
  6. This module contains global variable definitions shared by the
  7. various SMTP Service components.
  8. Author:
  9. KeithMo 07-Mar-1993 Created.
  10. --*/
  11. #define INCL_INETSRV_INCS
  12. #include "smtpinc.h"
  13. #include "smtpcli.hxx"
  14. #include "smtpout.hxx"
  15. #include "dropdir.hxx"
  16. #include "mailmsg_i.c"
  17. #include "mailmsgi_i.c"
  18. #include "aqueue_i.c"
  19. #include "aqstore.hxx"
  20. #include <dnsapi.h>
  21. //
  22. // Version string for this server
  23. //
  24. #define MSSMTP_VERSION_STR_IIS "Microsoft-IIS/K2"
  25. #define MSSMTP_VERSION_STR_W95 "Microsoft-PWS-95/K2"
  26. #define MSSMTP_VERSION_STR_NTW "Microsoft-PWS/K2"
  27. //
  28. // Set to the largest of the three
  29. //
  30. #define MSSMTP_VERSION_STR_MAX MSSMTP_VERSION_STR_W95
  31. //
  32. // Creates the version string
  33. //
  34. #define MAKE_VERSION_STRING( _s ) ("Server: " ##_s "\r\n")
  35. //
  36. // MIME version we say we support
  37. //
  38. #define SMTP_MIME_VERSION_STR "MIME-version: 1.0"
  39. #define SMTP_TEMP_DIR_NAME " "
  40. //
  41. // Server type string
  42. //
  43. CHAR g_szServerType[ sizeof(MSSMTP_VERSION_STR_MAX)];
  44. DWORD g_cbServerType = 0;
  45. CHAR szServerVersion[sizeof(MAKE_VERSION_STRING(MSSMTP_VERSION_STR_MAX))];
  46. DWORD cbServerVersionString = 0;
  47. DWORD g_ProductType = 5;
  48. PLATFORM_TYPE g_SmtpPlatformType = PtNtServer;
  49. //computer name
  50. CHAR g_ComputerName[MAX_PATH + 1];
  51. DWORD g_ComputerNameLength;
  52. // number of procs on system for thread mgmt.
  53. DWORD g_NumProcessors = 1;
  54. CHAR g_VersionString[128];
  55. CHAR g_Password[MAX_PATH + 1];
  56. CHAR g_UserName[MAX_PATH + 1];
  57. CHAR g_DomainName[MAX_PATH + 1];
  58. static char g_BoundaryChars [] = "0123456789abcdefghijklmnopqrstuvwxyz"
  59. "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  60. //Max Objects
  61. DWORD g_cMaxAddressObjects;
  62. DWORD g_cMaxPropertyBagObjects;
  63. DWORD g_cMaxMailObjects;
  64. DWORD g_cMaxEtrnObjects;
  65. DWORD g_cMaxRoutingThreads;
  66. // externs for cmmprops.lib and blockmgr.lib to control debug code
  67. DWORD g_fValidateSignatures = 0;
  68. DWORD g_fForceCrashOnError = 0;
  69. DWORD g_fFillPropertyPages = 0;
  70. DWORD g_cMaxConnectionObjs = 2000;
  71. BOOL g_CalledSrand;
  72. DWORD g_dwIncMsgId;
  73. // X5 189659 instrumentation
  74. DWORD g_fCrashOnInvalidSMTPConn = 0;
  75. //These buffers are associated with every incoming connection - so we
  76. //will need to have atleast those any plus a few more for use in Dir pickup
  77. //and large SSL buffers
  78. DWORD g_cMaxDirBuffers = 2500;
  79. //This buffer is now used primarily as WRITEBUFFER for every connection
  80. //We have decided to go with 32K buffer
  81. //NK** : Make this metabse readable
  82. DWORD g_cMaxDirChangeIoSize = SMTP_WRITE_BUFFER_SIZE;
  83. //loopback address
  84. DWORD g_LoopBackAddr;
  85. unsigned char GlobalIpBuffer[10000];
  86. CShareLockNH g_GlobalLock;
  87. SOCKET g_IpListSocket = INVALID_SOCKET;
  88. WSAOVERLAPPED WsaOverLapped;
  89. HANDLE g_ShutdownHandle = NULL;
  90. HANDLE g_TcpNotifyHandle = NULL;
  91. HANDLE g_FreeLibThreadHandle = NULL;
  92. CTcpRegIpList g_TcpRegIpList;
  93. //
  94. // Notification object used to watch for changes in CAPI stores
  95. //
  96. STORE_CHANGE_NOTIFIER *g_pCAPIStoreChangeNotifier;
  97. //
  98. // Miscellaneous data.
  99. //
  100. LARGE_INTEGER AllocationGranularity; // Page allocation granularity.
  101. HANDLE g_hSysAccToken = NULL;
  102. TCHAR * g_pszSmtpTempDirName; // Name of temporary directory.
  103. DWORD g_PickupWait;
  104. DWORD g_FreeLibInterval = 1; //Interval in min to wait before calling CoFreeUnusedLib
  105. DWORD g_UseMapiDriver = 0;
  106. LONG g_MaxFindThreads;
  107. //
  108. // Platform type
  109. //
  110. PLATFORM_TYPE SmtpPlatformType = PtNtServer;
  111. BOOL g_fIsWindows95 = FALSE;
  112. //
  113. // Statistics.
  114. // used to write statistics counter values to when instance is unknown
  115. //
  116. LPSMTP_SERVER_STATISTICS g_pSmtpStats;
  117. //
  118. // SEO Handle
  119. //
  120. IUnknown *g_punkSEOHandle;
  121. //
  122. // Externals for SEO
  123. //
  124. extern HRESULT SEOGetServiceHandle(IUnknown **);
  125. //
  126. // Generate the string storage space
  127. //
  128. #if 0
  129. # include "strconst.h"
  130. # define CStrM( FriendlyName, ActualString) \
  131. const char PSZ_ ## FriendlyName[] = ActualString;
  132. ConstantStringsForThisModule()
  133. # undef CStrM
  134. #endif
  135. DWORD SmtpDebug;
  136. extern "C" {
  137. BOOL g_IsShuttingDown = FALSE;
  138. }
  139. DWORD g_SmtpInitializeStatus = 0;
  140. TIME_ZONE_INFORMATION tzInfo;
  141. #define MAX_CONNECTION_OBJECTS 5000;
  142. BOOL GetMachineIpAddresses(void);
  143. DWORD TcpRegNotifyThread( LPDWORD lpdw );
  144. DWORD FreeLibThread( LPDWORD lpdw );
  145. //
  146. // eventlog object
  147. //
  148. CEventLogWrapper g_EventLog;
  149. //
  150. // Header Date time cache
  151. //
  152. //PCACHED_DATETIME_FORMATS g_pDateTimeCache = NULL;
  153. static TCHAR szParamPath[] = TEXT("System\\CurrentControlSet\\Services\\SmtpSvc\\Parameters");
  154. static WCHAR szParamPathW[] = L"System\\CurrentControlSet\\Services\\SmtpSvc\\Parameters";
  155. static TCHAR szMaxAddrObjects[] = TEXT("MaxAddressObjects");
  156. static WCHAR szMaxAddrObjectsW[] = L"MaxAddressObjects";
  157. static TCHAR szMaxPropertyBagObjects[] = TEXT("MaxPropertyBagObjects");
  158. static WCHAR szMaxPropertyBagObjectsW[] = L"MaxPropertyBagObjects";
  159. static TCHAR szMaxMailObjects[] = TEXT("MaxMailObjects");
  160. static WCHAR szMaxMailObjectsW[] = L"MaxMailObjects";
  161. static TCHAR szMaxEtrnObjects[] = TEXT("MaxEtrnObjects");
  162. static WCHAR szMaxEtrnObjectsW[] = L"MaxEtrnObjects";
  163. static TCHAR szDirBuffers[] = TEXT("MaxDirectoryBuffers");
  164. static WCHAR szDirBuffersW[] = L"MaxDirectoryBuffers";
  165. static TCHAR szDirBuffersSize[] = TEXT("DirectoryBuffSize");
  166. static WCHAR szDirBuffersSizeW[] = L"DirectoryBufferSize";
  167. static TCHAR szDirPendingIos[] = TEXT("NumDirPendingIos");
  168. static WCHAR szDirPendingIosW[] = L"NumDirPendingIos";
  169. static TCHAR szRoutingThreads[] = TEXT("RoutingThreads");
  170. static WCHAR szRoutingThreadsW[] = L"RoutingThreads";
  171. static TCHAR szProductType[] = TEXT("ProductType");
  172. static WCHAR szProductTypeW[] = L"ProductType";
  173. static TCHAR szResolverSockets[] = TEXT("NumDnsResolverSockets");
  174. static WCHAR szResolverSocketsW[] = L"NumDnsResolverSockets";
  175. static TCHAR szDnsSocketTimeout[] = TEXT("msDnsSocketTimeout");
  176. static WCHAR szDnsSocketTimeoutW[] = L"msDnsSocketTimeout";
  177. static TCHAR szPickupWait[] = TEXT("PickupWait");
  178. static WCHAR szPickupWaitW[] = L"PickupWait";
  179. static TCHAR szMaxFindThreads[] = TEXT("MaxFindThreads");
  180. static WCHAR szMaxFindThreadsW[] = L"MaxFindThreads";
  181. static TCHAR szFreeLibInterval[] = TEXT("FreeLibInterval");
  182. static WCHAR szFreeLibIntervalW[] = L"FreeLibInterval";
  183. static TCHAR szUseMapiDrv[] = TEXT("UseMapiDriver");
  184. static WCHAR szUseMapiDrvW[] = L"UseMapiDriver";
  185. static TCHAR szDnsErrorsBeforeFailover[] = TEXT("DnsErrorsBeforeFailover");
  186. static WCHAR szDnsErrorsBeforeFailoverW[] = L"DnsErrorsBeforeFailover";
  187. static TCHAR szDnsConnectsInProbation[] = TEXT("DnsConnectsInProbation");
  188. static WCHAR szDnsConnectsInProbationW[] = L"DnsConnectsInProbation";
  189. //
  190. // resolver globals
  191. //
  192. DWORD g_ResolverSockets = 10;
  193. DWORD g_DnsSocketTimeout = 60000;
  194. DWORD g_DnsErrorsBeforeFailover = 3;
  195. DWORD g_DnsConnectsInProbation = 2;
  196. typedef struct tagVERTAG {
  197. LPSTR pszTag;
  198. } VERTAG, *PVERTAG, FAR *LPVERTAG;
  199. VERTAG Tags[] = {
  200. // { "FileDescription" },
  201. // { "OriginalFilename" },
  202. // { "ProductName" },
  203. { "ProductVersion" },
  204. // { "LegalCopyright" },
  205. // { "LegalCopyright" },
  206. };
  207. #define NUM_TAGS (sizeof( Tags ) / sizeof( VERTAG ))
  208. BOOL GetRegistryDwordParameter(
  209. LPCSTR pcszParameterName,
  210. DWORD *pdwValue
  211. )
  212. {
  213. HKEY hKey = NULL;
  214. DWORD dwRes;
  215. DWORD dwType;
  216. DWORD dwLength;
  217. DWORD dwValue;
  218. BOOL fRes = FALSE;
  219. // Open the registry key
  220. dwRes = (DWORD)RegOpenKeyEx(
  221. HKEY_LOCAL_MACHINE,
  222. _T("Software\\Microsoft\\Exchange\\SmtpSvc"),
  223. 0,
  224. KEY_ALL_ACCESS,
  225. &hKey);
  226. if (dwRes == ERROR_SUCCESS)
  227. {
  228. // Adjust the buffer size for character type ...
  229. dwLength = sizeof(DWORD);
  230. dwRes = (DWORD)RegQueryValueEx(
  231. hKey,
  232. pcszParameterName,
  233. NULL,
  234. &dwType,
  235. (LPBYTE)&dwValue,
  236. &dwLength);
  237. if ((dwRes == ERROR_SUCCESS) && dwType == REG_DWORD)
  238. {
  239. *pdwValue = dwValue;
  240. fRes = TRUE;
  241. }
  242. _VERIFY(RegCloseKey(hKey) == NO_ERROR);
  243. }
  244. return(fRes);
  245. }
  246. //DWORD ConfigIMCService(void);
  247. DWORD SetVersionStrings( LPSTR lpszFile, LPSTR lpszTitle, LPSTR lpstrOut, DWORD cbOut )
  248. {
  249. static char sz[256], szFormat[256], sz2[256];
  250. int i;
  251. UINT uBytes;
  252. LPVOID lpMem;
  253. DWORD dw = 0, dwSize;
  254. HANDLE hMem;
  255. LPVOID lpsz;
  256. LPDWORD lpLang;
  257. DWORD dwLang2;
  258. BOOL bRC, bFileFound = FALSE;
  259. LPSTR lpstrOrig = lpstrOut ;
  260. //CharUpper( lpszTitle );
  261. if ( dwSize = GetFileVersionInfoSize( lpszFile, &dw ) ) {
  262. if ( hMem = GlobalAlloc( GMEM_MOVEABLE|GMEM_ZEROINIT, (UINT)dwSize ) ) {
  263. lpMem = GlobalLock(hMem);
  264. if (GetFileVersionInfo( lpszFile, 0, dwSize, lpMem ) &&
  265. VerQueryValue( lpMem, "\\VarFileInfo\\Translation",
  266. (LPVOID FAR *)&lpLang, &uBytes ) )
  267. {
  268. dwLang2 = MAKELONG( HIWORD(lpLang[0]), LOWORD(lpLang[0]) );
  269. for( i=0; i<NUM_TAGS; i++ ) {
  270. lpsz = 0 ;
  271. //
  272. // need to do the reverse because most winnt files are wrong
  273. //
  274. wsprintf( sz, "\\StringFileInfo\\%08lx\\%s", lpLang[0], Tags[i].pszTag );
  275. wsprintf( sz2, "\\StringFileInfo\\%08lx\\%s", dwLang2, Tags[i].pszTag );
  276. bRC = VerQueryValue( lpMem, sz, &lpsz, &uBytes ) ||
  277. VerQueryValue( lpMem, sz2, &lpsz, &uBytes ) ;
  278. if( lpsz != 0 )
  279. {
  280. if( uBytes+1 < cbOut )
  281. {
  282. uBytes = min( (UINT)lstrlen( (char*)lpsz ), uBytes ) ;
  283. CopyMemory( lpstrOut, lpsz, uBytes ) ;
  284. lpstrOut[uBytes++] = ' ' ;
  285. lpstrOut += uBytes ;
  286. cbOut -= uBytes ;
  287. }
  288. else
  289. {
  290. GlobalUnlock( hMem );
  291. GlobalFree( hMem );
  292. return (DWORD)(lpstrOut - lpstrOrig) ;
  293. }
  294. }
  295. }
  296. // version info from fixed struct
  297. bRC = VerQueryValue(lpMem,
  298. "\\",
  299. &lpsz,
  300. &uBytes );
  301. #define lpvs ((VS_FIXEDFILEINFO FAR *)lpsz)
  302. static char szVersion[] = "Version: %d.%d.%d.%d" ;
  303. if ( (cbOut > (sizeof( szVersion )*2)) && lpsz ) {
  304. CopyMemory( szFormat, szVersion, sizeof( szVersion ) ) ;
  305. //LoadString( hInst, IDS_VERSION, szFormat, sizeof(szFormat) );
  306. DWORD cbPrint = wsprintf( lpstrOut, szFormat, HIWORD(lpvs->dwFileVersionMS),
  307. LOWORD(lpvs->dwFileVersionMS),
  308. HIWORD(lpvs->dwFileVersionLS),
  309. LOWORD(lpvs->dwFileVersionLS) );
  310. lpstrOut += cbPrint ;
  311. }
  312. bFileFound = TRUE;
  313. } else {
  314. }
  315. GlobalUnlock( hMem );
  316. GlobalFree( hMem );
  317. } else {
  318. }
  319. } else {
  320. }
  321. DWORD dw2 = GetLastError() ;
  322. return (DWORD)(lpstrOut - lpstrOrig) ;
  323. }
  324. BOOL InitServerVersionString( VOID )
  325. {
  326. BOOL fRet = TRUE ;
  327. DWORD szSize;
  328. char szServerPath[MAX_PATH + 1];
  329. char * szOffset;
  330. CopyMemory(szServerPath, "c:\\", sizeof( "c:\\" ) ) ;
  331. g_VersionString [0] = '\0';
  332. HMODULE hModule = GetModuleHandle( "smtpsvc.dll" ) ;
  333. if( hModule != 0 )
  334. {
  335. if( !GetModuleFileName( hModule, szServerPath, sizeof( szServerPath ) ) )
  336. {
  337. lstrcpy( szServerPath, "c:\\") ;
  338. }
  339. else
  340. {
  341. szSize = SetVersionStrings(szServerPath, "", g_VersionString, 128 );
  342. szOffset = strstr(g_VersionString, "Version");
  343. if(szOffset)
  344. {
  345. //Move interesting part of string (including the
  346. //terminating NULL) to front of g_VersionString.
  347. MoveMemory(g_VersionString, szOffset,
  348. szSize+1 - (szOffset - g_VersionString));
  349. }
  350. }
  351. }
  352. return TRUE ;
  353. }
  354. BOOL GetGlobalRegistrySettings(void)
  355. {
  356. BOOL fRet = TRUE;
  357. HKEY hkeySmtp = NULL;
  358. HKEY hkeySub = NULL;
  359. DWORD dwErr;
  360. DWORD dwDisp;
  361. DWORD dwMaxFindThreads;
  362. TraceFunctEnterEx((LPARAM)NULL, "GetGlobalRegistrySettings");
  363. dwErr = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szParamPath, NULL, NULL,
  364. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeySmtp, &dwDisp);
  365. if (dwErr != ERROR_SUCCESS)
  366. {
  367. SmtpLogEventEx(SMTP_EVENT_CANNOT_OPEN_SVC_REGKEY, (const char *)SMTP_PARAMETERS_KEY, dwErr);
  368. TraceFunctLeave();
  369. SetLastError(dwErr);
  370. return FALSE;
  371. }
  372. g_cMaxAddressObjects = ReadRegistryDword(hkeySmtp, szMaxAddrObjects, 100000);
  373. StateTrace((LPARAM)NULL, "g_cMaxAddressObjects = %u", g_cMaxAddressObjects);
  374. //NK ** We atleast need as many buffers as many connections we accept
  375. //so I have now tied it to that value
  376. //g_cMaxDirBuffers = ReadRegistryDword(hkeySmtp, szDirBuffers, 5000);
  377. //g_cMaxDirChangeIoSize = ReadRegistryDword(hkeySmtp, szDirBuffersSize, MAX_WRITE_FILE_BLOCK);
  378. g_ResolverSockets = ReadRegistryDword(hkeySmtp, szResolverSockets, 10);
  379. g_DnsSocketTimeout = ReadRegistryDword(hkeySmtp, szDnsSocketTimeout, 60000);
  380. g_DnsErrorsBeforeFailover = ReadRegistryDword(hkeySmtp, szDnsErrorsBeforeFailover, 3);
  381. g_DnsConnectsInProbation = ReadRegistryDword(hkeySmtp, szDnsConnectsInProbation, 2);
  382. g_PickupWait = ReadRegistryDword(hkeySmtp, szPickupWait, 200);
  383. // don't let them make this wait more than 5 secs. that is too much.
  384. if (g_PickupWait > 5000)
  385. {
  386. g_PickupWait = 5000;
  387. }
  388. //In seems like after the call to unload, the dlls get physically unloaded
  389. //11 min after that. So I am setting the interval by default to 11.
  390. g_FreeLibInterval = ReadRegistryDword(hkeySmtp,szFreeLibInterval, 11);
  391. // don't let them make this wait more than 60 min. that is too much.
  392. if (g_FreeLibInterval > 60)
  393. {
  394. g_FreeLibInterval = 60;
  395. }
  396. dwMaxFindThreads = ReadRegistryDword(hkeySmtp, szMaxFindThreads, 3);
  397. // don't want this to be bigger than the routing threads, but we want at least one.
  398. if (dwMaxFindThreads > 3)
  399. {
  400. dwMaxFindThreads = 3;
  401. }
  402. else if (dwMaxFindThreads <= 0)
  403. {
  404. dwMaxFindThreads = 1;
  405. }
  406. g_MaxFindThreads = dwMaxFindThreads;
  407. RegCloseKey(hkeySmtp);
  408. TraceFunctLeaveEx((LPARAM)NULL);
  409. return fRet;
  410. }
  411. void IpAddressListCallBack (DWORD dwError, DWORD cbTransferred, LPWSAOVERLAPPED LpOverlapped,
  412. DWORD dwFlags)
  413. {
  414. DWORD wsError = 0;
  415. DWORD bytesReturned = 0;
  416. GetMachineIpAddresses();
  417. wsError = WSAIoctl(g_IpListSocket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL,
  418. 0, &bytesReturned, &WsaOverLapped, IpAddressListCallBack);
  419. }
  420. BOOL GetMachineIpAddresses(void)
  421. {
  422. DWORD bytesReturned = 0;
  423. DWORD wsError = 0;
  424. BOOL fRet = FALSE;
  425. g_GlobalLock.ExclusiveLock();
  426. ZeroMemory((void *)GlobalIpBuffer, sizeof(GlobalIpBuffer));
  427. if(g_IpListSocket != INVALID_SOCKET)
  428. {
  429. wsError = WSAIoctl(g_IpListSocket, SIO_ADDRESS_LIST_QUERY, NULL, 0, (LPVOID) GlobalIpBuffer,
  430. sizeof(GlobalIpBuffer), &bytesReturned, NULL, NULL);
  431. if(wsError == 0)
  432. {
  433. fRet = TRUE;
  434. }
  435. }
  436. g_GlobalLock.ExclusiveUnlock();
  437. return fRet;
  438. }
  439. BOOL IsIpInGlobalList(DWORD IpAddress)
  440. {
  441. INT AddressCount = 0;
  442. SOCKET_ADDRESS_LIST * ptr = NULL;
  443. sockaddr_in * Current = NULL;
  444. char Scratch[100];
  445. TraceFunctEnterEx((LPARAM)NULL, "IsIpInGlobalList");
  446. g_GlobalLock.ShareLock();
  447. Scratch[0] = '\0';
  448. ptr = (SOCKET_ADDRESS_LIST *)GlobalIpBuffer;
  449. for (AddressCount = 0; AddressCount < ptr->iAddressCount;AddressCount++)
  450. {
  451. Current = (sockaddr_in *) ptr->Address[AddressCount].lpSockaddr;
  452. if(Current)
  453. {
  454. DebugTrace((LPARAM)NULL," Address - %s", inet_ntoa( Current->sin_addr));
  455. if(Current->sin_addr.s_addr == IpAddress)
  456. {
  457. InetNtoa(*(struct in_addr *) &Current->sin_addr.s_addr, Scratch);
  458. ErrorTrace((LPARAM) NULL, "IpAddress %s is one of mine - Failing connection", Scratch);
  459. g_GlobalLock.ShareUnlock();
  460. TraceFunctLeaveEx((LPARAM)NULL);
  461. return TRUE;
  462. }
  463. }
  464. }
  465. g_GlobalLock.ShareUnlock();
  466. InetNtoa(*(struct in_addr *) &IpAddress, Scratch);
  467. DebugTrace((LPARAM) NULL, "IpAddress %s is not one of mine ", Scratch);
  468. TraceFunctLeaveEx((LPARAM)NULL);
  469. return FALSE;
  470. }
  471. void VerifyFQDNWithGlobalIp(DWORD InstanceId, char * szFQDomainName)
  472. {
  473. INT AddressCount = 0;
  474. SOCKET_ADDRESS_LIST * ptr = NULL;
  475. sockaddr_in * Current = NULL;
  476. char Scratch[100];
  477. Scratch[0] = '\0';
  478. CONST CHAR *apszMsgs[2];
  479. CHAR achInstance[20];
  480. CHAR achIPAddr[20];
  481. PHOSTENT pH = NULL;
  482. //Get the current instnace id
  483. wsprintf( achInstance,
  484. "%lu",
  485. InstanceId );
  486. apszMsgs[1] = achInstance;
  487. g_GlobalLock.ShareLock();
  488. ptr = (SOCKET_ADDRESS_LIST *)GlobalIpBuffer;
  489. for (AddressCount = 0; AddressCount < ptr->iAddressCount;AddressCount++)
  490. {
  491. Current = (sockaddr_in *) ptr->Address[AddressCount].lpSockaddr;
  492. if(Current)
  493. {
  494. ((PSMTP_IIS_SERVICE) g_pInetSvc)->StartHintFunction();
  495. //For each IP address find the host name
  496. pH = gethostbyaddr( (char*)(&((PSOCKADDR_IN)Current)->sin_addr), 4, PF_INET );
  497. if(pH == NULL)
  498. {
  499. SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN, 0, (const CHAR **)NULL, 0 );
  500. }
  501. else if(_strnicmp(pH->h_name,szFQDomainName,strlen(szFQDomainName)))
  502. {
  503. wsprintf( achIPAddr,"%s",inet_ntoa( Current->sin_addr));
  504. apszMsgs[0] = achIPAddr;
  505. SmtpLogEvent( SMTP_EVENT_UNRESOLVED_FQDN,2,apszMsgs,0 );
  506. }
  507. }
  508. }
  509. g_GlobalLock.ShareUnlock();
  510. }
  511. //
  512. // Public functions.
  513. //
  514. APIERR
  515. InitializeGlobals(
  516. VOID
  517. )
  518. /*++
  519. Routine Description:
  520. Initializes global shared variables. Some values are
  521. initialized with constants, others are read from the
  522. configuration registry.
  523. Arguments:
  524. None.
  525. Return Value:
  526. Win32
  527. --*/
  528. {
  529. DWORD err;
  530. DWORD MaxConnections;
  531. SYSTEM_INFO systemInfo;
  532. HRESULT hr = S_OK;
  533. DWORD wsError = 0;
  534. DWORD bytesReturned = 0;
  535. DWORD dwThreadId = 0;
  536. TraceFunctEnter( "InitializeGlobals" );
  537. g_CalledSrand = FALSE;
  538. g_dwIncMsgId = 0;
  539. g_ShutdownHandle = CreateEvent( NULL, TRUE, FALSE, NULL );
  540. if(g_ShutdownHandle == NULL)
  541. {
  542. err = GetLastError();
  543. ErrorTrace(0, "Cannot allocate shutdown handle. err: %u", err);
  544. _ASSERT(err != NO_ERROR);
  545. if(err == NO_ERROR)
  546. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  547. goto error_exit;
  548. }
  549. g_TcpNotifyHandle =
  550. CreateThread( NULL,
  551. 0,
  552. (LPTHREAD_START_ROUTINE)TcpRegNotifyThread,
  553. NULL,
  554. 0,
  555. &dwThreadId );
  556. if (g_TcpNotifyHandle == NULL )
  557. {
  558. err = GetLastError();
  559. ErrorTrace(0, "Cannot create notify thread. err: %u", err);
  560. _ASSERT(err != NO_ERROR);
  561. if(err == NO_ERROR)
  562. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  563. goto error_exit;
  564. }
  565. hr = g_EventLog.Initialize("smtpsvc");
  566. if (FAILED(hr)) {
  567. // do nothing
  568. }
  569. g_IpListSocket = socket (AF_INET, SOCK_STREAM, 0);
  570. if(g_IpListSocket != INVALID_SOCKET)
  571. {
  572. GetMachineIpAddresses();
  573. wsError = WSAIoctl(g_IpListSocket, SIO_ADDRESS_LIST_CHANGE, NULL, 0, NULL,
  574. 0, &bytesReturned, &WsaOverLapped, IpAddressListCallBack);
  575. if(wsError == 0)
  576. {
  577. //fRet = TRUE;
  578. }
  579. }
  580. //
  581. // read the global registry settings
  582. //
  583. g_SmtpPlatformType = IISGetPlatformType();
  584. if(!GetGlobalRegistrySettings())
  585. {
  586. FatalTrace(NULL, "Could not read global reg settings!");
  587. TraceFunctLeave();
  588. return ERROR_SERVICE_DISABLED;
  589. }
  590. //thread to periodically call free ununsed libraries
  591. //so dll's can be unloaded
  592. g_FreeLibThreadHandle =
  593. CreateThread( NULL,
  594. 0,
  595. (LPTHREAD_START_ROUTINE)FreeLibThread,
  596. NULL,
  597. 0,
  598. &dwThreadId );
  599. if (g_FreeLibThreadHandle == NULL )
  600. {
  601. err = GetLastError();
  602. ErrorTrace(0, "Cannot create Free Library thread. err: %u", err);
  603. _ASSERT(err != NO_ERROR);
  604. if(err == NO_ERROR)
  605. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  606. goto error_exit;
  607. }
  608. //
  609. // do global SEO initialization
  610. //
  611. hr = SEOGetServiceHandle(&g_punkSEOHandle);
  612. if (FAILED(hr))
  613. {
  614. ErrorTrace(0, "SEOGetServiceHandle returned %x", hr);
  615. // we're in trouble here. we'll try and continue on, but server events
  616. // probably won't work right
  617. g_punkSEOHandle = NULL;
  618. //SmtpLogEventSimple(SEO_INIT_FAILED, hr);
  619. }
  620. //
  621. // Initialize the server version string based on the platform type
  622. //
  623. InitServerVersionString();
  624. SmtpPlatformType = IISGetPlatformType();
  625. switch ( SmtpPlatformType )
  626. {
  627. case PtNtWorkstation:
  628. lstrcpy(szServerVersion,MAKE_VERSION_STRING(MSSMTP_VERSION_STR_NTW));
  629. lstrcpy(g_szServerType, MSSMTP_VERSION_STR_NTW);
  630. break;
  631. default:
  632. //
  633. // Either server or unhandled platform type!
  634. //
  635. DBG_ASSERT(InetIsNtServer(SmtpPlatformType));
  636. lstrcpy(szServerVersion,MAKE_VERSION_STRING(MSSMTP_VERSION_STR_IIS));
  637. lstrcpy(g_szServerType, MSSMTP_VERSION_STR_IIS);
  638. }
  639. g_cbServerType = lstrlen( g_szServerType);
  640. cbServerVersionString = lstrlen(szServerVersion);
  641. //store the computer name
  642. g_ComputerNameLength = MAX_PATH;
  643. if (!GetComputerName(g_ComputerName, &g_ComputerNameLength))
  644. {
  645. err = GetLastError();
  646. ErrorTrace((LPARAM)NULL, "GetComputerName() failed with err %d", err);
  647. TraceFunctLeave();
  648. return err;
  649. }
  650. // number of processors on the system.
  651. GetSystemInfo( &systemInfo );
  652. g_NumProcessors = systemInfo.dwNumberOfProcessors;
  653. g_LoopBackAddr = inet_addr ("127.0.0.1");
  654. g_pSmtpStats = NULL;
  655. //find out what the max connection paramater is
  656. MaxConnections = MAX_CONNECTION_OBJECTS;
  657. DebugTrace(NULL, "g_cMaxConnectionObjs = %d", g_cMaxConnectionObjs);
  658. //allocate some SMTP_CONNECTION objects from CPOOL
  659. if (!SMTP_CONNECTION::Pool.ReserveMemory( g_cMaxConnectionObjs, sizeof(SMTP_CONNECTION) ) )
  660. {
  661. err = GetLastError();
  662. ErrorTrace(0, "ReserveMemory failed for SMTP_CONNECTION. err: %u", err);
  663. _ASSERT(err != NO_ERROR);
  664. if(err == NO_ERROR)
  665. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  666. goto error_exit;
  667. }
  668. g_SmtpInitializeStatus |= INITIALIZE_INBOUNDPOOL;
  669. //allocate some SMTP_CONNECTION objects from CPOOL
  670. if (!SMTP_CONNOUT::Pool.ReserveMemory(MaxConnections, sizeof(SMTP_CONNOUT) ) )
  671. {
  672. err = GetLastError();
  673. ErrorTrace(0, "ReserveMemory failed for SMTP_CONNOUT. err: %u", err);
  674. _ASSERT(err != NO_ERROR);
  675. if(err == NO_ERROR)
  676. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  677. goto error_exit;
  678. }
  679. g_SmtpInitializeStatus |= INITIALIZE_OUTBOUNDPOOL;
  680. //allocate some CAddr objects from CPOOL
  681. if (!CAddr::Pool.ReserveMemory(1000, sizeof(CAddr) ) )
  682. {
  683. err = GetLastError();
  684. ErrorTrace(0, "ReserveMemory failed for CAddr. err: %u", err);
  685. _ASSERT(err != NO_ERROR);
  686. if(err == NO_ERROR)
  687. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  688. goto error_exit;
  689. }
  690. g_SmtpInitializeStatus |= INITIALIZE_ADDRESSPOOL;
  691. if (!CAsyncMx::Pool.ReserveMemory(3000, sizeof(CAsyncMx)))
  692. {
  693. err = GetLastError();
  694. ErrorTrace(0, "ReserveMemory failed for CBuffer. err: %u", err);
  695. _ASSERT(err != NO_ERROR);
  696. if(err == NO_ERROR)
  697. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  698. goto error_exit;
  699. }
  700. g_SmtpInitializeStatus |= INITIALIZE_CASYNCMX;
  701. if (!CAsyncSmtpDns::Pool.ReserveMemory(4000, sizeof(CAsyncSmtpDns)))
  702. {
  703. err = GetLastError();
  704. ErrorTrace(0, "ReserveMemory failed for CBuffer. err: %u", err);
  705. _ASSERT(err != NO_ERROR);
  706. if(err == NO_ERROR)
  707. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  708. goto error_exit;
  709. }
  710. g_SmtpInitializeStatus |= INITIALIZE_CASYNCDNS;
  711. //
  712. // Initialize the file handle cache
  713. //
  714. if (!InitializeCache()) {
  715. err = GetLastError();
  716. ErrorTrace(0, "InitializeCache failed err: %u", err);
  717. _ASSERT(err != NO_ERROR);
  718. if(err == NO_ERROR)
  719. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  720. goto error_exit;
  721. }
  722. g_SmtpInitializeStatus |= INITIALIZE_FILEHC;
  723. if (!CBuffer::Pool.ReserveMemory(g_cMaxDirBuffers, sizeof(CBuffer)))
  724. {
  725. err = GetLastError();
  726. ErrorTrace(0, "ReserveMemory failed for CBuffer. err: %u", err);
  727. _ASSERT(err != NO_ERROR);
  728. if(err == NO_ERROR)
  729. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  730. goto error_exit;
  731. }
  732. g_SmtpInitializeStatus |= INITIALIZE_CBUFFERPOOL;
  733. if (!CIoBuffer::Pool.ReserveMemory(g_cMaxDirBuffers, g_cMaxDirChangeIoSize))
  734. {
  735. err = GetLastError();
  736. ErrorTrace(0, "ReserveMemory failed for CIOBuffer. err: %u", err);
  737. _ASSERT(err != NO_ERROR);
  738. if(err == NO_ERROR)
  739. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  740. goto error_exit;
  741. }
  742. g_SmtpInitializeStatus |= INITIALIZE_CIOBUFFPOOL;
  743. if (!CBlockMemoryAccess::m_Pool.ReserveMemory(2000, sizeof(BLOCK_HEAP_NODE)))
  744. {
  745. err = GetLastError();
  746. ErrorTrace(0, "ReserveMemory failed for CBlockMemoryAccess. err: %u", err);
  747. _ASSERT(err != NO_ERROR);
  748. if(err == NO_ERROR)
  749. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  750. goto error_exit;
  751. }
  752. g_SmtpInitializeStatus |= INITIALIZE_CBLOCKMGR;
  753. if (!CDropDir::m_Pool.ReserveMemory(1000, sizeof(CDropDir)))
  754. {
  755. err = GetLastError();
  756. ErrorTrace(0, "ReserveMemory failed for CDropDir. err: %u", err);
  757. _ASSERT(err != NO_ERROR);
  758. if(err == NO_ERROR)
  759. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  760. goto error_exit;
  761. }
  762. g_SmtpInitializeStatus |= INITIALIZE_CDROPDIR;
  763. //
  764. // Create the CAPI store notification object
  765. //
  766. g_pCAPIStoreChangeNotifier = new STORE_CHANGE_NOTIFIER();
  767. if ( g_pCAPIStoreChangeNotifier == NULL )
  768. {
  769. err = GetLastError();
  770. ErrorTrace(0, "Failed to create CAPIStoreChange notifier err: %u", err);
  771. _ASSERT(err != NO_ERROR);
  772. if(err == NO_ERROR)
  773. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  774. goto error_exit;
  775. }
  776. if (!CEncryptCtx::Initialize(
  777. "SmtpSvc",
  778. (struct IMDCOM*) g_pInetSvc->QueryMDObject(),
  779. (PVOID) (&g_SmtpSMC)))
  780. {
  781. err = GetLastError();
  782. ErrorTrace(0, "Initializing SSL Context failed. err: %u", err);
  783. _ASSERT(err != NO_ERROR);
  784. if(err == NO_ERROR)
  785. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  786. goto error_exit;
  787. }
  788. g_SmtpInitializeStatus |= INITIALIZE_SSLCONTEXT;
  789. if (!CSecurityCtx::Initialize(FALSE, FALSE))
  790. {
  791. err = GetLastError();
  792. ErrorTrace(NULL, "CSecurityCtx::Initialize failed, %u", err);
  793. if(err == NO_ERROR)
  794. SetLastError (ERROR_NOT_ENOUGH_MEMORY);
  795. goto error_exit;
  796. }
  797. g_SmtpInitializeStatus |= INITIALIZE_CSECURITY;
  798. GetTimeZoneInformation(&tzInfo);
  799. // Enable/disable 189659 instrumentation
  800. GetRegistryDwordParameter(
  801. _T("CrashOnInvalidSMTPConn"),
  802. &g_fCrashOnInvalidSMTPConn);
  803. TraceFunctLeave();
  804. return NO_ERROR;
  805. error_exit:
  806. err = GetLastError();
  807. if(err == NO_ERROR)
  808. {
  809. SetLastError(ERROR_PATH_NOT_FOUND);
  810. err = ERROR_PATH_NOT_FOUND;
  811. }
  812. TraceFunctLeave();
  813. return err;
  814. } // InitializeGlobals
  815. VOID
  816. TerminateGlobals(
  817. VOID
  818. )
  819. /*++
  820. Routine Description:
  821. Terminates global shared variables.
  822. Arguments:
  823. None.
  824. Return Value:
  825. None.
  826. --*/
  827. {
  828. if(g_ShutdownHandle)
  829. {
  830. SetEvent(g_ShutdownHandle);
  831. }
  832. if(g_SmtpInitializeStatus & INITIALIZE_INBOUNDPOOL)
  833. {
  834. //finally, release all our memory
  835. SMTP_CONNECTION::Pool.ReleaseMemory();
  836. }
  837. if(g_SmtpInitializeStatus & INITIALIZE_OUTBOUNDPOOL)
  838. {
  839. SMTP_CONNOUT::Pool.ReleaseMemory();
  840. }
  841. if(g_SmtpInitializeStatus & INITIALIZE_ADDRESSPOOL)
  842. {
  843. CAddr::Pool.ReleaseMemory();
  844. }
  845. if(g_SmtpInitializeStatus & INITIALIZE_CBUFFERPOOL)
  846. {
  847. //finally, release all our memory
  848. CBuffer::Pool.ReleaseMemory();
  849. }
  850. if(g_SmtpInitializeStatus & INITIALIZE_CIOBUFFPOOL)
  851. {
  852. //finally, release all our memory
  853. CIoBuffer::Pool.ReleaseMemory();
  854. }
  855. if (g_SmtpInitializeStatus & INITIALIZE_CDROPDIR)
  856. {
  857. CDropDir::m_Pool.ReleaseMemory();
  858. }
  859. if ( g_pCAPIStoreChangeNotifier )
  860. {
  861. delete g_pCAPIStoreChangeNotifier;
  862. g_pCAPIStoreChangeNotifier = NULL;
  863. }
  864. if (g_SmtpInitializeStatus & INITIALIZE_SSLCONTEXT) {
  865. CEncryptCtx::Terminate();
  866. }
  867. if (g_SmtpInitializeStatus & INITIALIZE_CSECURITY)
  868. CSecurityCtx::Terminate();
  869. if(g_SmtpInitializeStatus & INITIALIZE_CASYNCMX)
  870. {
  871. //finally, release all our memory
  872. CAsyncMx::Pool.ReleaseMemory();
  873. }
  874. if(g_SmtpInitializeStatus & INITIALIZE_CASYNCDNS)
  875. {
  876. //finally, release all our memory
  877. CAsyncSmtpDns::Pool.ReleaseMemory();
  878. }
  879. if (g_SmtpInitializeStatus & INITIALIZE_FILEHC) {
  880. TerminateCache();
  881. }
  882. if(g_SmtpInitializeStatus & INITIALIZE_CBLOCKMGR)
  883. {
  884. //finally, release all our memory
  885. CBlockMemoryAccess::m_Pool.ReleaseMemory();
  886. }
  887. if( g_pSmtpStats != NULL )
  888. {
  889. delete g_pSmtpStats;
  890. g_pSmtpStats = NULL;
  891. }
  892. if(g_IpListSocket != INVALID_SOCKET)
  893. {
  894. closesocket (g_IpListSocket);
  895. g_IpListSocket = INVALID_SOCKET;
  896. }
  897. UnLoadQueueDriver();
  898. //
  899. // do global SEO cleanup
  900. //
  901. if (g_punkSEOHandle != NULL)
  902. {
  903. g_punkSEOHandle->Release();
  904. g_punkSEOHandle = NULL;
  905. }
  906. if(g_TcpNotifyHandle != NULL)
  907. {
  908. WaitForSingleObject(g_TcpNotifyHandle, INFINITE);
  909. CloseHandle(g_TcpNotifyHandle);
  910. g_TcpNotifyHandle = NULL;
  911. }
  912. if(g_FreeLibThreadHandle != NULL)
  913. {
  914. WaitForSingleObject(g_FreeLibThreadHandle, INFINITE);
  915. CloseHandle(g_FreeLibThreadHandle);
  916. g_FreeLibThreadHandle = NULL;
  917. }
  918. if(g_ShutdownHandle != NULL)
  919. {
  920. CloseHandle(g_ShutdownHandle);
  921. g_ShutdownHandle = NULL;
  922. }
  923. } // TerminateGlobals
  924. //
  925. // Given a directory path, this subroutine will create the direct layer by layer
  926. //
  927. BOOL CreateLayerDirectory( char * str )
  928. {
  929. BOOL fReturn = TRUE;
  930. char Tmp [MAX_PATH + 1];
  931. do
  932. {
  933. INT index=0;
  934. INT iLength = lstrlen(str) + 1;
  935. // first find the index for the first directory
  936. if ( iLength > 2 )
  937. {
  938. if ( str[1] == _T(':'))
  939. {
  940. // assume the first character is driver letter
  941. if ( str[2] == _T('\\'))
  942. {
  943. index = 2;
  944. } else
  945. {
  946. index = 1;
  947. }
  948. } else if ( str[0] == _T('\\'))
  949. {
  950. if ( str[1] == _T('\\'))
  951. {
  952. BOOL fFound = FALSE;
  953. INT i;
  954. INT nNum = 0;
  955. // unc name
  956. for (i = 2; i < iLength; i++ )
  957. {
  958. if ( str[i]==_T('\\'))
  959. {
  960. // find it
  961. nNum ++;
  962. if ( nNum == 2 )
  963. {
  964. fFound = TRUE;
  965. break;
  966. }
  967. }
  968. }
  969. if ( fFound )
  970. {
  971. index = i;
  972. } else
  973. {
  974. // bad name
  975. break;
  976. }
  977. } else
  978. {
  979. index = 1;
  980. }
  981. }
  982. } else if ( str[0] == _T('\\'))
  983. {
  984. index = 0;
  985. }
  986. // okay ... build directory
  987. do
  988. {
  989. // find next one
  990. do
  991. {
  992. if ( index < ( iLength - 1))
  993. {
  994. index ++;
  995. } else
  996. {
  997. break;
  998. }
  999. } while ( str[index] != _T('\\'));
  1000. TCHAR szCurrentDir[MAX_PATH+1];
  1001. GetCurrentDirectory( MAX_PATH+1, szCurrentDir );
  1002. lstrcpyn(Tmp, str, ( index + 1 ));
  1003. if ( !SetCurrentDirectory( Tmp))
  1004. {
  1005. if (( fReturn = CreateDirectory( Tmp, NULL )) != TRUE )
  1006. {
  1007. break;
  1008. }
  1009. }
  1010. SetCurrentDirectory( szCurrentDir );
  1011. if ( index >= ( iLength - 1 ))
  1012. {
  1013. fReturn = TRUE;
  1014. break;
  1015. }
  1016. } while ( TRUE );
  1017. } while (FALSE);
  1018. return(fReturn);
  1019. }
  1020. void GenerateMessageId (char * Buffer, DWORD BuffLen)
  1021. {
  1022. //Temporary stuff
  1023. DWORD MsgIdLen = 20;
  1024. if(BuffLen < MsgIdLen)
  1025. MsgIdLen = BuffLen;
  1026. if( !g_CalledSrand )
  1027. {
  1028. srand( GetTickCount() );
  1029. g_CalledSrand = TRUE;
  1030. }
  1031. lstrcpyn (Buffer, g_ComputerName, (MsgIdLen - 1));
  1032. DWORD Loop = lstrlen(Buffer);
  1033. while (Loop < (MsgIdLen - 1) )
  1034. {
  1035. Buffer[Loop] = g_BoundaryChars[rand() % (sizeof(g_BoundaryChars) - 1)];
  1036. Loop++;
  1037. }
  1038. Buffer [Loop] = '\0';
  1039. }
  1040. DWORD GetIncreasingMsgId()
  1041. {
  1042. return( InterlockedIncrement( (LONG*)&g_dwIncMsgId ) );
  1043. }
  1044. DWORD FreeLibThread( LPDWORD lpdw )
  1045. {
  1046. DWORD dw = 0;
  1047. DWORD dwWaitMillisec = g_FreeLibInterval * 1000 * 60;
  1048. TraceFunctEnterEx((LPARAM) NULL, "FreeLibThread");
  1049. for ( ;; )
  1050. {
  1051. dw = WaitForSingleObject(g_ShutdownHandle,
  1052. dwWaitMillisec );
  1053. switch( dw )
  1054. {
  1055. //
  1056. // normal shutdown signalled
  1057. //
  1058. case WAIT_OBJECT_0:
  1059. ErrorTrace((LPARAM) NULL, "Exiting FreeLibThread for hShutdownEvent");
  1060. return 0;
  1061. //
  1062. // Timeout occured
  1063. //
  1064. case WAIT_TIMEOUT:
  1065. CoFreeUnusedLibraries();
  1066. break;
  1067. default:
  1068. ErrorTrace((LPARAM) NULL, "Exiting FreeLibThread for default reasons");
  1069. return 1;
  1070. }
  1071. }
  1072. return 2;
  1073. }
  1074. #define NUM_REG_THREAD_OBJECTS 2
  1075. DWORD TcpRegNotifyThread( LPDWORD lpdw )
  1076. {
  1077. HANDLE Handles[NUM_REG_THREAD_OBJECTS];
  1078. PIP_ARRAY aipServers =NULL;
  1079. PLIST_ENTRY pEntry = NULL;
  1080. CTcpRegIpList * pIpEntry = NULL;
  1081. CTcpRegIpList *IpList = NULL;
  1082. HKEY hKey = NULL;
  1083. DWORD dw = 0;
  1084. TraceFunctEnterEx((LPARAM) NULL, "TcpRegNotifyThread");
  1085. Handles[0] = g_ShutdownHandle;
  1086. Handles[1] = CreateEvent( NULL, FALSE, FALSE, NULL );
  1087. if ( Handles[1] == NULL )
  1088. {
  1089. return 1;
  1090. }
  1091. DnsGetDnsServerList( (PIP_ARRAY *) &aipServers );
  1092. if (aipServers != NULL)
  1093. {
  1094. g_TcpRegIpList.Update(aipServers);
  1095. DnsApiFree(aipServers);
  1096. }
  1097. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1098. "System\\CurrentControlSet\\Services\\Tcpip",
  1099. 0,
  1100. KEY_READ,
  1101. &hKey ) != ERROR_SUCCESS )
  1102. {
  1103. ErrorTrace((LPARAM) NULL, "RegNotifyThread RegOpenKeyEx failed %d", GetLastError());
  1104. CloseHandle( Handles[1] );
  1105. return 1;
  1106. }
  1107. for ( ;; )
  1108. {
  1109. if ( RegNotifyChangeKeyValue(hKey,
  1110. TRUE,
  1111. REG_NOTIFY_CHANGE_ATTRIBUTES |
  1112. REG_NOTIFY_CHANGE_LAST_SET,
  1113. Handles[1],
  1114. TRUE ) != ERROR_SUCCESS )
  1115. {
  1116. ErrorTrace((LPARAM) NULL, "RegNotifyThread RegNotifyChangeKeyValue failed %d", GetLastError());
  1117. RegCloseKey( hKey );
  1118. CloseHandle( Handles[1] );
  1119. return 1;
  1120. }
  1121. dw = WaitForMultipleObjects(NUM_REG_THREAD_OBJECTS,
  1122. Handles,
  1123. FALSE,
  1124. INFINITE );
  1125. switch( dw )
  1126. {
  1127. //
  1128. // normal signalled event
  1129. //
  1130. case WAIT_OBJECT_0:
  1131. //close all the handles
  1132. RegCloseKey( hKey );
  1133. CloseHandle( Handles[1] );
  1134. Handles[1] = NULL;
  1135. hKey = NULL;
  1136. g_TcpRegIpList.Update(NULL);
  1137. ErrorTrace((LPARAM) NULL, "Exiting TcpRegNotifyThread for hShutdownEvent");
  1138. return 0;
  1139. //
  1140. // signalled that our registry keys have changed
  1141. //
  1142. case WAIT_OBJECT_0+1:
  1143. DnsGetDnsServerList( &aipServers );
  1144. g_TcpRegIpList.Update(aipServers);
  1145. if(aipServers)
  1146. DnsApiFree(aipServers);
  1147. break;
  1148. default:
  1149. RegCloseKey( hKey );
  1150. CloseHandle( Handles[1] );
  1151. return 1;
  1152. }
  1153. }
  1154. RegCloseKey( hKey );
  1155. CloseHandle( Handles[1] );
  1156. return 2;
  1157. }